summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2010-12-16 12:54:24 -0800
committerMike Lockwood <lockwood@android.com>2010-12-16 15:35:36 -0800
commit076e05b488e40fdd946f0d35137fe66a576efe09 (patch)
treec2b732777b51e1f6d8ba92047c2446bd0f2d0582 /media
parentdcaa10cd361a543cfa93bbb5c53444f437bd07a4 (diff)
downloadframeworks_base-076e05b488e40fdd946f0d35137fe66a576efe09.zip
frameworks_base-076e05b488e40fdd946f0d35137fe66a576efe09.tar.gz
frameworks_base-076e05b488e40fdd946f0d35137fe66a576efe09.tar.bz2
MediaScanner: Add support for scanning empty directories
Currently the media scanner does not create database entries for directories unless they contain a file that is scanned. Fixing this so we provide a consistent view of the world to MTP. Change-Id: Ia776acfeae23192183e7192d63cdc34d830ea889 Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/MediaScanner.java117
-rw-r--r--media/java/android/media/MediaScannerClient.java4
-rw-r--r--media/jni/android_media_MediaScanner.cpp8
-rw-r--r--media/libmedia/MediaScanner.cpp16
4 files changed, 79 insertions, 66 deletions
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 63ec6b2..365fd65 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -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;
- }
+ public FileCacheEntry beginFile(String path, String mimeType, long lastModified,
+ long fileSize, boolean isDirectory) {
+ mMimeType = mimeType;
+ mFileType = 0;
+ mFileSize = fileSize;
- // 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)) {
+ 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;
}
- 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;
+
+ // 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;
+ }
}
}
- }
- mMimeType = mimeType;
- mFileType = 0;
- mFileSize = fileSize;
-
- // try mimeType first, if it is specified
- if (mimeType != null) {
- mFileType = MediaFile.getFileTypeForMimeType(mimeType);
- }
+ // 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 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);
+ 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);
diff --git a/media/java/android/media/MediaScannerClient.java b/media/java/android/media/MediaScannerClient.java
index 258c3b4..ac326ef 100644
--- a/media/java/android/media/MediaScannerClient.java
+++ b/media/java/android/media/MediaScannerClient.java
@@ -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);
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index fd0b233..a5176fa 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -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());
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index c31b622..5ec573e 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -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;
}
}