Merge "MediaScanner: Add support for scanning empty directories"
This commit is contained in:
committed by
Android (Google) Code Review
commit
28cfb113da
@@ -71,7 +71,8 @@ public:
|
||||
bool addStringTag(const char* name, const char* value);
|
||||
void endFile();
|
||||
|
||||
virtual bool scanFile(const char* path, long long lastModified, long long fileSize) = 0;
|
||||
virtual bool scanFile(const char* path, long long lastModified,
|
||||
long long fileSize, bool isDirectory) = 0;
|
||||
virtual bool handleStringTag(const char* name, const char* value) = 0;
|
||||
virtual bool setMimeType(const char* mimeType) = 0;
|
||||
virtual bool addNoMediaFolder(const char* path) = 0;
|
||||
|
||||
@@ -407,55 +407,60 @@ public class MediaScanner
|
||||
private long mFileSize;
|
||||
private String mWriter;
|
||||
|
||||
public FileCacheEntry beginFile(String path, String mimeType, long lastModified, long fileSize) {
|
||||
|
||||
// special case certain file names
|
||||
// I use regionMatches() instead of substring() below
|
||||
// to avoid memory allocation
|
||||
int lastSlash = path.lastIndexOf('/');
|
||||
if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
|
||||
// ignore those ._* files created by MacOS
|
||||
if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ignore album art files created by Windows Media Player:
|
||||
// Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg and AlbumArt_{...}_Small.jpg
|
||||
if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
|
||||
if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
|
||||
path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
|
||||
return null;
|
||||
}
|
||||
int length = path.length() - lastSlash - 1;
|
||||
if ((length == 17 && path.regionMatches(true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
|
||||
(length == 10 && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FileCacheEntry beginFile(String path, String mimeType, long lastModified,
|
||||
long fileSize, boolean isDirectory) {
|
||||
mMimeType = mimeType;
|
||||
mFileType = 0;
|
||||
mFileSize = fileSize;
|
||||
|
||||
// try mimeType first, if it is specified
|
||||
if (mimeType != null) {
|
||||
mFileType = MediaFile.getFileTypeForMimeType(mimeType);
|
||||
}
|
||||
if (!isDirectory) {
|
||||
// special case certain file names
|
||||
// I use regionMatches() instead of substring() below
|
||||
// to avoid memory allocation
|
||||
int lastSlash = path.lastIndexOf('/');
|
||||
if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
|
||||
// ignore those ._* files created by MacOS
|
||||
if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if mimeType was not specified, compute file type based on file extension.
|
||||
if (mFileType == 0) {
|
||||
MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
|
||||
if (mediaFileType != null) {
|
||||
mFileType = mediaFileType.fileType;
|
||||
if (mMimeType == null) {
|
||||
mMimeType = mediaFileType.mimeType;
|
||||
// ignore album art files created by Windows Media Player:
|
||||
// Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
|
||||
// and AlbumArt_{...}_Small.jpg
|
||||
if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
|
||||
if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
|
||||
path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
|
||||
return null;
|
||||
}
|
||||
int length = path.length() - lastSlash - 1;
|
||||
if ((length == 17 && path.regionMatches(
|
||||
true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
|
||||
(length == 10
|
||||
&& path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) {
|
||||
mFileType = getFileTypeFromDrm(path);
|
||||
// try mimeType first, if it is specified
|
||||
if (mimeType != null) {
|
||||
mFileType = MediaFile.getFileTypeForMimeType(mimeType);
|
||||
}
|
||||
|
||||
// if mimeType was not specified, compute file type based on file extension.
|
||||
if (mFileType == 0) {
|
||||
MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
|
||||
if (mediaFileType != null) {
|
||||
mFileType = mediaFileType.fileType;
|
||||
if (mMimeType == null) {
|
||||
mMimeType = mediaFileType.mimeType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) {
|
||||
mFileType = getFileTypeFromDrm(path);
|
||||
}
|
||||
}
|
||||
|
||||
String key = path;
|
||||
@@ -470,7 +475,9 @@ public class MediaScanner
|
||||
FileCacheEntry entry = mFileCache.get(key);
|
||||
if (entry == null) {
|
||||
Uri tableUri;
|
||||
if (MediaFile.isVideoFileType(mFileType)) {
|
||||
if (isDirectory) {
|
||||
tableUri = mFilesUri;
|
||||
} else if (MediaFile.isVideoFileType(mFileType)) {
|
||||
tableUri = mVideoUri;
|
||||
} else if (MediaFile.isImageFileType(mFileType)) {
|
||||
tableUri = mImagesUri;
|
||||
@@ -479,7 +486,8 @@ public class MediaScanner
|
||||
} else {
|
||||
tableUri = mFilesUri;
|
||||
}
|
||||
entry = new FileCacheEntry(tableUri, 0, path, 0, 0);
|
||||
entry = new FileCacheEntry(tableUri, 0, path, 0,
|
||||
(isDirectory ? MtpConstants.FORMAT_ASSOCIATION : 0));
|
||||
mFileCache.put(key, entry);
|
||||
}
|
||||
entry.mSeenInFileSystem = true;
|
||||
@@ -514,22 +522,19 @@ public class MediaScanner
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void scanFile(String path, long lastModified, long fileSize) {
|
||||
public void scanFile(String path, long lastModified, long fileSize, boolean isDirectory) {
|
||||
// This is the callback funtion from native codes.
|
||||
// Log.v(TAG, "scanFile: "+path);
|
||||
doScanFile(path, null, lastModified, fileSize, false);
|
||||
}
|
||||
|
||||
public void scanFile(String path, String mimeType, long lastModified, long fileSize) {
|
||||
doScanFile(path, mimeType, lastModified, fileSize, false);
|
||||
doScanFile(path, null, lastModified, fileSize, isDirectory, false);
|
||||
}
|
||||
|
||||
public Uri doScanFile(String path, String mimeType, long lastModified,
|
||||
long fileSize, boolean scanAlways) {
|
||||
long fileSize, boolean isDirectory, boolean scanAlways) {
|
||||
Uri result = null;
|
||||
// long t1 = System.currentTimeMillis();
|
||||
try {
|
||||
FileCacheEntry entry = beginFile(path, mimeType, lastModified, fileSize);
|
||||
FileCacheEntry entry = beginFile(path, mimeType, lastModified,
|
||||
fileSize, isDirectory);
|
||||
// rescan for metadata if file was modified since last scan
|
||||
if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
|
||||
String lowpath = path.toLowerCase();
|
||||
@@ -775,7 +780,11 @@ public class MediaScanner
|
||||
values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
|
||||
}
|
||||
if (tableUri == mFilesUri) {
|
||||
values.put(Files.FileColumns.FORMAT, MediaFile.getFormatCode(entry.mPath, mMimeType));
|
||||
int format = entry.mFormat;
|
||||
if (format == 0) {
|
||||
format = MediaFile.getFormatCode(entry.mPath, mMimeType);
|
||||
}
|
||||
values.put(Files.FileColumns.FORMAT, format);
|
||||
}
|
||||
// new file, insert it
|
||||
result = mMediaProvider.insert(tableUri, values);
|
||||
@@ -1060,8 +1069,7 @@ public class MediaScanner
|
||||
boolean fileMissing = false;
|
||||
|
||||
if (!entry.mSeenInFileSystem && !MtpConstants.isAbstractObject(entry.mFormat)) {
|
||||
if (entry.mFormat != MtpConstants.FORMAT_ASSOCIATION &&
|
||||
inScanDirectory(path, directories)) {
|
||||
if (inScanDirectory(path, directories)) {
|
||||
// we didn't see this file in the scan directory.
|
||||
fileMissing = true;
|
||||
} else {
|
||||
@@ -1180,7 +1188,7 @@ public class MediaScanner
|
||||
long lastModifiedSeconds = file.lastModified() / 1000;
|
||||
|
||||
// always scan the file, so we can return the content://media Uri for existing files
|
||||
return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(), true);
|
||||
return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),false, true);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
|
||||
return null;
|
||||
@@ -1227,7 +1235,8 @@ public class MediaScanner
|
||||
long lastModifiedSeconds = file.lastModified() / 1000;
|
||||
|
||||
// always scan the file, so we can return the content://media Uri for existing files
|
||||
mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(), true);
|
||||
mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(),
|
||||
(format == MtpConstants.FORMAT_ASSOCIATION), true);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
|
||||
|
||||
@@ -21,9 +21,7 @@ package android.media;
|
||||
*/
|
||||
public interface MediaScannerClient
|
||||
{
|
||||
public void scanFile(String path, long lastModified, long fileSize);
|
||||
|
||||
public void scanFile(String path, String mimeType, long lastModified, long fileSize);
|
||||
public void scanFile(String path, long lastModified, long fileSize, boolean isDirectory);
|
||||
|
||||
public void addNoMediaFolder(String path);
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
}
|
||||
else {
|
||||
mScanFileMethodID = env->GetMethodID(mediaScannerClientInterface, "scanFile",
|
||||
"(Ljava/lang/String;JJ)V");
|
||||
"(Ljava/lang/String;JJZ)V");
|
||||
mHandleStringTagMethodID = env->GetMethodID(mediaScannerClientInterface, "handleStringTag",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType",
|
||||
@@ -78,12 +78,14 @@ public:
|
||||
}
|
||||
|
||||
// returns true if it succeeded, false if an exception occured in the Java code
|
||||
virtual bool scanFile(const char* path, long long lastModified, long long fileSize)
|
||||
virtual bool scanFile(const char* path, long long lastModified,
|
||||
long long fileSize, bool isDirectory)
|
||||
{
|
||||
jstring pathStr;
|
||||
if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
|
||||
|
||||
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified, fileSize);
|
||||
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
|
||||
fileSize, isDirectory);
|
||||
|
||||
mEnv->DeleteLocalRef(pathStr);
|
||||
return (!mEnv->ExceptionCheck());
|
||||
|
||||
@@ -84,6 +84,7 @@ status_t MediaScanner::doProcessDirectory(
|
||||
// place to copy file or directory name
|
||||
char* fileSpot = path + strlen(path);
|
||||
struct dirent* entry;
|
||||
struct stat statbuf;
|
||||
|
||||
// ignore directories that contain a ".nomedia" file
|
||||
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
|
||||
@@ -125,7 +126,6 @@ status_t MediaScanner::doProcessDirectory(
|
||||
// If the type is unknown, stat() the file instead.
|
||||
// This is sometimes necessary when accessing NFS mounted filesystems, but
|
||||
// could be needed in other cases well.
|
||||
struct stat statbuf;
|
||||
if (stat(path, &statbuf) == 0) {
|
||||
if (S_ISREG(statbuf.st_mode)) {
|
||||
type = DT_REG;
|
||||
@@ -142,8 +142,15 @@ status_t MediaScanner::doProcessDirectory(
|
||||
// for example, the Mac ".Trashes" directory
|
||||
if (name[0] == '.') continue;
|
||||
|
||||
// report the directory to the client
|
||||
if (stat(path, &statbuf) == 0) {
|
||||
client.scanFile(path, statbuf.st_mtime, 0, true);
|
||||
}
|
||||
|
||||
// and now process its contents
|
||||
strcat(fileSpot, "/");
|
||||
int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client, exceptionCheck, exceptionEnv);
|
||||
int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client,
|
||||
exceptionCheck, exceptionEnv);
|
||||
if (err) {
|
||||
// pass exceptions up - ignore other errors
|
||||
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
|
||||
@@ -151,11 +158,8 @@ status_t MediaScanner::doProcessDirectory(
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
struct stat statbuf;
|
||||
stat(path, &statbuf);
|
||||
if (statbuf.st_size > 0) {
|
||||
client.scanFile(path, statbuf.st_mtime, statbuf.st_size);
|
||||
}
|
||||
client.scanFile(path, statbuf.st_mtime, statbuf.st_size, false);
|
||||
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user