Merge "MediaScanner: Add support for scanning empty directories"

This commit is contained in:
Mike Lockwood
2010-12-17 11:22:12 -08:00
committed by Android (Google) Code Review
5 changed files with 83 additions and 69 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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());

View File

@@ -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;
}
}