diff options
| author | 2019-01-28 16:01:50 +0000 | |
|---|---|---|
| committer | 2019-01-28 16:01:50 +0000 | |
| commit | 31f977a44344b8930143f16ab7f2fee4c5302d33 (patch) | |
| tree | dee7b5715ea330cc40b75ad5b67996c534fba819 | |
| parent | 175e2f24a2f052a92197185360383494a7886f8d (diff) | |
| parent | f7c79b4f06fef85879dd6adfd4062ce0132664ca (diff) | |
Merge "Update FileObserver to be able to watch multiple files."
| -rw-r--r-- | api/current.txt | 8 | ||||
| -rw-r--r-- | core/java/android/os/FileObserver.java | 107 | ||||
| -rw-r--r-- | core/jni/android_util_FileObserver.cpp | 38 |
3 files changed, 116 insertions, 37 deletions
diff --git a/api/current.txt b/api/current.txt index 0544b27bb903..361ee74becdd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34408,8 +34408,12 @@ package android.os { } public abstract class FileObserver { - ctor public FileObserver(String); - ctor public FileObserver(String, int); + ctor @Deprecated public FileObserver(String); + ctor public FileObserver(@NonNull java.io.File); + ctor public FileObserver(@NonNull java.util.List<java.io.File>); + ctor @Deprecated public FileObserver(String, int); + ctor public FileObserver(@NonNull java.io.File, int); + ctor public FileObserver(@NonNull java.util.List<java.io.File>, int); method protected void finalize(); method public abstract void onEvent(int, @Nullable String); method public void startWatching(); diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java index dd85e1584f0e..da0389578e15 100644 --- a/core/java/android/os/FileObserver.java +++ b/core/java/android/os/FileObserver.java @@ -16,11 +16,15 @@ package android.os; +import android.annotation.NonNull; import android.annotation.Nullable; import android.util.Log; +import java.io.File; import java.lang.ref.WeakReference; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; /** * Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>) @@ -28,7 +32,7 @@ import java.util.HashMap; * the device (including this one). FileObserver is an abstract class; * subclasses must implement the event handler {@link #onEvent(int, String)}. * - * <p>Each FileObserver instance monitors a single file or directory. + * <p>Each FileObserver instance can monitor multiple files or directories. * If a directory is monitored, events will be triggered for all files and * subdirectories inside the monitored directory.</p> * @@ -86,21 +90,32 @@ public abstract class FileObserver { observe(m_fd); } - public int startWatching(String path, int mask, FileObserver observer) { - int wfd = startWatching(m_fd, path, mask); + public int[] startWatching(List<File> files, int mask, FileObserver observer) { + final int count = files.size(); + final String[] paths = new String[count]; + for (int i = 0; i < count; ++i) { + paths[i] = files.get(i).getAbsolutePath(); + } + final int[] wfds = new int[count]; + Arrays.fill(wfds, -1); + + startWatching(m_fd, paths, mask, wfds); - Integer i = new Integer(wfd); - if (wfd >= 0) { - synchronized (m_observers) { - m_observers.put(i, new WeakReference(observer)); + final WeakReference<FileObserver> fileObserverWeakReference = + new WeakReference<>(observer); + synchronized (m_observers) { + for (int wfd : wfds) { + if (wfd >= 0) { + m_observers.put(wfd, fileObserverWeakReference); + } } } - return i; + return wfds; } - public void stopWatching(int descriptor) { - stopWatching(m_fd, descriptor); + public void stopWatching(int[] descriptors) { + stopWatching(m_fd, descriptors); } public void onEvent(int wfd, int mask, String path) { @@ -129,8 +144,8 @@ public abstract class FileObserver { private native int init(); private native void observe(int fd); - private native int startWatching(int fd, String path, int mask); - private native void stopWatching(int fd, int wfd); + private native void startWatching(int fd, String[] paths, int mask, int[] wfds); + private native void stopWatching(int fd, int[] wfds); } private static ObserverThread s_observerThread; @@ -141,15 +156,34 @@ public abstract class FileObserver { } // instance - private String m_path; - private Integer m_descriptor; - private int m_mask; + private final List<File> mFiles; + private int[] mDescriptors; + private final int mMask; /** * Equivalent to FileObserver(path, FileObserver.ALL_EVENTS). + * + * @deprecated use {@link #FileObserver(File)} instead. */ + @Deprecated public FileObserver(String path) { - this(path, ALL_EVENTS); + this(new File(path)); + } + + /** + * Equivalent to FileObserver(file, FileObserver.ALL_EVENTS). + */ + public FileObserver(@NonNull File file) { + this(Arrays.asList(file)); + } + + /** + * Equivalent to FileObserver(paths, FileObserver.ALL_EVENTS). + * + * @param files The files or directories to monitor + */ + public FileObserver(@NonNull List<File> files) { + this(files, ALL_EVENTS); } /** @@ -159,11 +193,36 @@ public abstract class FileObserver { * * @param path The file or directory to monitor * @param mask The event or events (added together) to watch for + * + * @deprecated use {@link #FileObserver(File, int)} instead. */ + @Deprecated public FileObserver(String path, int mask) { - m_path = path; - m_mask = mask; - m_descriptor = -1; + this(new File(path), mask); + } + + /** + * Create a new file observer for a certain file or directory. + * Monitoring does not start on creation! You must call + * {@link #startWatching()} before you will receive events. + * + * @param file The file or directory to monitor + * @param mask The event or events (added together) to watch for + */ + public FileObserver(@NonNull File file, int mask) { + this(Arrays.asList(file), mask); + } + + /** + * Version of {@link #FileObserver(File, int)} that allows callers to monitor + * multiple files or directories. + * + * @param files The files or directories to monitor + * @param mask The event or events (added together) to watch for + */ + public FileObserver(@NonNull List<File> files, int mask) { + mFiles = files; + mMask = mask; } protected void finalize() { @@ -176,8 +235,8 @@ public abstract class FileObserver { * If monitoring is already started, this call has no effect. */ public void startWatching() { - if (m_descriptor < 0) { - m_descriptor = s_observerThread.startWatching(m_path, m_mask, this); + if (mDescriptors == null) { + mDescriptors = s_observerThread.startWatching(mFiles, mMask, this); } } @@ -187,9 +246,9 @@ public abstract class FileObserver { * monitoring is already stopped, this call has no effect. */ public void stopWatching() { - if (m_descriptor >= 0) { - s_observerThread.stopWatching(m_descriptor); - m_descriptor = -1; + if (mDescriptors != null) { + s_observerThread.stopWatching(mDescriptors); + mDescriptors = null; } } diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp index 6f975b23e5bd..d25192a57228 100644 --- a/core/jni/android_util_FileObserver.cpp +++ b/core/jni/android_util_FileObserver.cpp @@ -16,6 +16,8 @@ */ #include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedPrimitiveArray.h> +#include <nativehelper/ScopedUtfChars.h> #include "jni.h" #include "utils/Log.h" #include "utils/misc.h" @@ -98,31 +100,45 @@ static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd #endif } -static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask) +static void android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, + jobjectArray pathStrings, jint mask, + jintArray wfdArray) { - int res = -1; + ScopedIntArrayRW wfds(env, wfdArray); + if (wfds.get() == nullptr) { + jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRW"); + } #if defined(__linux__) if (fd >= 0) { - const char* path = env->GetStringUTFChars(pathString, NULL); + size_t count = wfds.size(); + for (jsize i = 0; i < count; ++i) { + jstring pathString = (jstring) env->GetObjectArrayElement(pathStrings, i); - res = inotify_add_watch(fd, path, mask); + ScopedUtfChars path(env, pathString); - env->ReleaseStringUTFChars(pathString, path); + wfds[i] = inotify_add_watch(fd, path.c_str(), mask); + } } #endif - - return res; } -static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd) +static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, + jint fd, jintArray wfdArray) { #if defined(__linux__) - inotify_rm_watch((int)fd, (uint32_t)wfd); + ScopedIntArrayRO wfds(env, wfdArray); + if (wfds.get() == nullptr) { + jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRO"); + } + size_t count = wfds.size(); + for (size_t i = 0; i < count; ++i) { + inotify_rm_watch((int)fd, (uint32_t)wfds[i]); + } #endif } @@ -131,8 +147,8 @@ static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "init", "()I", (void*)android_os_fileobserver_init }, { "observe", "(I)V", (void*)android_os_fileobserver_observe }, - { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching }, - { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching } + { "startWatching", "(I[Ljava/lang/String;I[I)V", (void*)android_os_fileobserver_startWatching }, + { "stopWatching", "(I[I)V", (void*)android_os_fileobserver_stopWatching } }; |