Merge "Use inotify to update DocumentsUI." into klp-dev
This commit is contained in:
@ -84,7 +84,6 @@ import com.google.android.collect.Lists;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the documents inside a single directory.
|
* Display the documents inside a single directory.
|
||||||
@ -127,9 +126,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
private static final String EXTRA_QUERY = "query";
|
private static final String EXTRA_QUERY = "query";
|
||||||
private static final String EXTRA_IGNORE_STATE = "ignoreState";
|
private static final String EXTRA_IGNORE_STATE = "ignoreState";
|
||||||
|
|
||||||
private static AtomicInteger sLoaderId = new AtomicInteger(4000);
|
private final int mLoaderId = 42;
|
||||||
|
|
||||||
private final int mLoaderId = sLoaderId.incrementAndGet();
|
|
||||||
|
|
||||||
public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
|
public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
|
||||||
show(fm, TYPE_NORMAL, root, doc, null, anim);
|
show(fm, TYPE_NORMAL, root, doc, null, anim);
|
||||||
|
@ -16,14 +16,17 @@
|
|||||||
|
|
||||||
package com.android.externalstorage;
|
package com.android.externalstorage;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.AssetFileDescriptor;
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.database.MatrixCursor.RowBuilder;
|
import android.database.MatrixCursor.RowBuilder;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.FileObserver;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.storage.StorageManager;
|
import android.os.storage.StorageManager;
|
||||||
import android.os.storage.StorageVolume;
|
import android.os.storage.StorageVolume;
|
||||||
@ -49,6 +52,8 @@ import java.util.Map;
|
|||||||
public class ExternalStorageProvider extends DocumentsProvider {
|
public class ExternalStorageProvider extends DocumentsProvider {
|
||||||
private static final String TAG = "ExternalStorage";
|
private static final String TAG = "ExternalStorage";
|
||||||
|
|
||||||
|
private static final boolean LOG_INOTIFY = false;
|
||||||
|
|
||||||
public static final String AUTHORITY = "com.android.externalstorage.documents";
|
public static final String AUTHORITY = "com.android.externalstorage.documents";
|
||||||
|
|
||||||
// docId format: root:path/to/file
|
// docId format: root:path/to/file
|
||||||
@ -83,6 +88,9 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
@GuardedBy("mRootsLock")
|
@GuardedBy("mRootsLock")
|
||||||
private HashMap<String, File> mIdToPath;
|
private HashMap<String, File> mIdToPath;
|
||||||
|
|
||||||
|
@GuardedBy("mObservers")
|
||||||
|
private Map<File, DirectoryObserver> mObservers = Maps.newHashMap();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreate() {
|
public boolean onCreate() {
|
||||||
mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
|
mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
|
||||||
@ -327,8 +335,9 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
public Cursor queryChildDocuments(
|
public Cursor queryChildDocuments(
|
||||||
String parentDocumentId, String[] projection, String sortOrder)
|
String parentDocumentId, String[] projection, String sortOrder)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
|
|
||||||
final File parent = getFileForDocId(parentDocumentId);
|
final File parent = getFileForDocId(parentDocumentId);
|
||||||
|
final MatrixCursor result = new DirectoryCursor(
|
||||||
|
resolveDocumentProjection(projection), parentDocumentId, parent);
|
||||||
for (File file : parent.listFiles()) {
|
for (File file : parent.listFiles()) {
|
||||||
includeFile(result, null, file);
|
includeFile(result, null, file);
|
||||||
}
|
}
|
||||||
@ -431,4 +440,86 @@ public class ExternalStorageProvider extends DocumentsProvider {
|
|||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startObserving(File file, Uri notifyUri) {
|
||||||
|
synchronized (mObservers) {
|
||||||
|
DirectoryObserver observer = mObservers.get(file);
|
||||||
|
if (observer == null) {
|
||||||
|
observer = new DirectoryObserver(
|
||||||
|
file, getContext().getContentResolver(), notifyUri);
|
||||||
|
observer.startWatching();
|
||||||
|
mObservers.put(file, observer);
|
||||||
|
}
|
||||||
|
observer.mRefCount++;
|
||||||
|
|
||||||
|
if (LOG_INOTIFY) Log.d(TAG, "after start: " + observer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopObserving(File file) {
|
||||||
|
synchronized (mObservers) {
|
||||||
|
DirectoryObserver observer = mObservers.get(file);
|
||||||
|
if (observer == null) return;
|
||||||
|
|
||||||
|
observer.mRefCount--;
|
||||||
|
if (observer.mRefCount == 0) {
|
||||||
|
mObservers.remove(file);
|
||||||
|
observer.stopWatching();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_INOTIFY) Log.d(TAG, "after stop: " + observer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DirectoryObserver extends FileObserver {
|
||||||
|
private static final int NOTIFY_EVENTS = ATTRIB | CLOSE_WRITE | MOVED_FROM | MOVED_TO
|
||||||
|
| CREATE | DELETE | DELETE_SELF | MOVE_SELF;
|
||||||
|
|
||||||
|
private final File mFile;
|
||||||
|
private final ContentResolver mResolver;
|
||||||
|
private final Uri mNotifyUri;
|
||||||
|
|
||||||
|
private int mRefCount = 0;
|
||||||
|
|
||||||
|
public DirectoryObserver(File file, ContentResolver resolver, Uri notifyUri) {
|
||||||
|
super(file.getAbsolutePath(), NOTIFY_EVENTS);
|
||||||
|
mFile = file;
|
||||||
|
mResolver = resolver;
|
||||||
|
mNotifyUri = notifyUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(int event, String path) {
|
||||||
|
if ((event & NOTIFY_EVENTS) != 0) {
|
||||||
|
if (LOG_INOTIFY) Log.d(TAG, "onEvent() " + event + " at " + path);
|
||||||
|
mResolver.notifyChange(mNotifyUri, null, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DirectoryObserver{file=" + mFile.getAbsolutePath() + ", ref=" + mRefCount + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DirectoryCursor extends MatrixCursor {
|
||||||
|
private final File mFile;
|
||||||
|
|
||||||
|
public DirectoryCursor(String[] columnNames, String docId, File file) {
|
||||||
|
super(columnNames);
|
||||||
|
|
||||||
|
final Uri notifyUri = DocumentsContract.buildChildDocumentsUri(
|
||||||
|
AUTHORITY, docId);
|
||||||
|
setNotificationUri(getContext().getContentResolver(), notifyUri);
|
||||||
|
|
||||||
|
mFile = file;
|
||||||
|
startObserving(mFile, notifyUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
super.close();
|
||||||
|
stopObserving(mFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user