summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/mediascanner.h5
-rw-r--r--media/java/android/media/MediaScanner.java192
-rw-r--r--media/java/android/media/MediaScannerClient.java5
-rw-r--r--media/jni/android_media_MediaScanner.cpp29
-rw-r--r--media/libmedia/MediaScanner.cpp24
5 files changed, 124 insertions, 131 deletions
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index df5be32..765c039 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -55,7 +55,7 @@ private:
status_t doProcessDirectory(
char *path, int pathRemaining, MediaScannerClient &client,
- ExceptionCheck exceptionCheck, void *exceptionEnv);
+ bool noMedia, ExceptionCheck exceptionCheck, void *exceptionEnv);
MediaScanner(const MediaScanner &);
MediaScanner &operator=(const MediaScanner &);
@@ -72,10 +72,9 @@ public:
void endFile();
virtual bool scanFile(const char* path, long long lastModified,
- long long fileSize, bool isDirectory) = 0;
+ long long fileSize, bool isDirectory, bool noMedia) = 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;
protected:
void convertValues(uint32_t encoding);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index a7ac9ed..80cc94e 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -422,9 +422,10 @@ public class MediaScanner
private long mFileSize;
private String mWriter;
private int mCompilation;
+ private boolean mNoMedia; // flag to suppress file from appearing in media tables
public FileCacheEntry beginFile(String path, String mimeType, long lastModified,
- long fileSize, boolean isDirectory) {
+ long fileSize, boolean isDirectory, boolean noMedia) {
mMimeType = mimeType;
mFileType = 0;
mFileSize = fileSize;
@@ -435,28 +436,31 @@ public class MediaScanner
// 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;
+ if (!noMedia) {
+ // ignore those ._* files created by MacOS
+ if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
+ noMedia = true;
}
- 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)) {
+ noMedia = true;
+ }
+ 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))) {
+ noMedia = true;
+ }
}
}
}
+ mNoMedia = noMedia;
// try mimeType first, if it is specified
if (mimeType != null) {
@@ -523,36 +527,41 @@ public class MediaScanner
return entry;
}
- public void scanFile(String path, long lastModified, long fileSize, boolean isDirectory) {
+ public void scanFile(String path, long lastModified, long fileSize,
+ boolean isDirectory, boolean noMedia) {
// This is the callback funtion from native codes.
// Log.v(TAG, "scanFile: "+path);
- doScanFile(path, null, lastModified, fileSize, isDirectory, false);
+ doScanFile(path, null, lastModified, fileSize, isDirectory, false, noMedia);
}
public Uri doScanFile(String path, String mimeType, long lastModified,
- long fileSize, boolean isDirectory, boolean scanAlways) {
+ long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) {
Uri result = null;
// long t1 = System.currentTimeMillis();
try {
FileCacheEntry entry = beginFile(path, mimeType, lastModified,
- fileSize, isDirectory);
+ fileSize, isDirectory, noMedia);
// rescan for metadata if file was modified since last scan
if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
- String lowpath = path.toLowerCase();
- boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0);
- boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0);
- boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0);
- boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0);
- boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
- (!ringtones && !notifications && !alarms && !podcasts);
-
- // we only extract metadata for audio and video files
- if (MediaFile.isAudioFileType(mFileType)
- || MediaFile.isVideoFileType(mFileType)) {
- processFile(path, mimeType, this);
- }
+ if (noMedia) {
+ result = endFile(entry, false, false, false, false, false);
+ } else {
+ String lowpath = path.toLowerCase();
+ boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0);
+ boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0);
+ boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0);
+ boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0);
+ boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
+ (!ringtones && !notifications && !alarms && !podcasts);
+
+ // we only extract metadata for audio and video files
+ if (MediaFile.isAudioFileType(mFileType)
+ || MediaFile.isVideoFileType(mFileType)) {
+ processFile(path, mimeType, this);
+ }
- result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
+ result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
+ }
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
@@ -689,27 +698,31 @@ public class MediaScanner
map.put(MediaStore.MediaColumns.SIZE, mFileSize);
map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
- if (MediaFile.isVideoFileType(mFileType)) {
- map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING));
- map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaStore.UNKNOWN_STRING));
- map.put(Video.Media.DURATION, mDuration);
- // FIXME - add RESOLUTION
- } else if (MediaFile.isImageFileType(mFileType)) {
- // FIXME - add DESCRIPTION
- } else if (MediaFile.isAudioFileType(mFileType)) {
- map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
- mArtist : MediaStore.UNKNOWN_STRING);
- map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
- mAlbumArtist.length() > 0) ? mAlbumArtist : null);
- map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ?
- mAlbum : MediaStore.UNKNOWN_STRING);
- map.put(Audio.Media.COMPOSER, mComposer);
- if (mYear != 0) {
- map.put(Audio.Media.YEAR, mYear);
+ if (!mNoMedia) {
+ if (MediaFile.isVideoFileType(mFileType)) {
+ map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0
+ ? mArtist : MediaStore.UNKNOWN_STRING));
+ map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0
+ ? mAlbum : MediaStore.UNKNOWN_STRING));
+ map.put(Video.Media.DURATION, mDuration);
+ // FIXME - add RESOLUTION
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ // FIXME - add DESCRIPTION
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
+ mArtist : MediaStore.UNKNOWN_STRING);
+ map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
+ mAlbumArtist.length() > 0) ? mAlbumArtist : null);
+ map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ?
+ mAlbum : MediaStore.UNKNOWN_STRING);
+ map.put(Audio.Media.COMPOSER, mComposer);
+ if (mYear != 0) {
+ map.put(Audio.Media.YEAR, mYear);
+ }
+ map.put(Audio.Media.TRACK, mTrack);
+ map.put(Audio.Media.DURATION, mDuration);
+ map.put(Audio.Media.COMPILATION, mCompilation);
}
- map.put(Audio.Media.TRACK, mTrack);
- map.put(Audio.Media.DURATION, mDuration);
- map.put(Audio.Media.COMPILATION, mCompilation);
}
return map;
}
@@ -719,7 +732,7 @@ public class MediaScanner
throws RemoteException {
// update database
- // use album artist if artist is missing
+ // use album artist if artist is missing
if (mArtist == null || mArtist.length() == 0) {
mArtist = mAlbumArtist;
}
@@ -761,7 +774,7 @@ public class MediaScanner
values.put(Audio.Media.IS_ALARM, alarms);
values.put(Audio.Media.IS_MUSIC, music);
values.put(Audio.Media.IS_PODCAST, podcasts);
- } else if (mFileType == MediaFile.FILE_TYPE_JPEG) {
+ } else if (mFileType == MediaFile.FILE_TYPE_JPEG && !mNoMedia) {
ExifInterface exif = null;
try {
exif = new ExifInterface(entry.mPath);
@@ -814,12 +827,14 @@ public class MediaScanner
}
Uri tableUri = mFilesUri;
- if (MediaFile.isVideoFileType(mFileType)) {
- tableUri = mVideoUri;
- } else if (MediaFile.isImageFileType(mFileType)) {
- tableUri = mImagesUri;
- } else if (MediaFile.isAudioFileType(mFileType)) {
- tableUri = mAudioUri;
+ if (!mNoMedia) {
+ if (MediaFile.isVideoFileType(mFileType)) {
+ tableUri = mVideoUri;
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ tableUri = mImagesUri;
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ tableUri = mAudioUri;
+ }
}
Uri result = null;
if (rowId == 0) {
@@ -930,25 +945,6 @@ public class MediaScanner
}
}
- public void addNoMediaFolder(String path) {
- ContentValues values = new ContentValues();
- values.put(MediaStore.Images.ImageColumns.DATA, "");
- String [] pathSpec = new String[] {path + '%'};
- try {
- // These tables have DELETE_FILE triggers that delete the file from the
- // sd card when deleting the database entry. We don't want to do this in
- // this case, since it would cause those files to be removed if a .nomedia
- // file was added after the fact, when in that case we only want the database
- // entries to be removed.
- mMediaProvider.update(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values,
- MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
- mMediaProvider.update(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values,
- MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
- } catch (RemoteException e) {
- throw new RuntimeException();
- }
- }
-
private int getFileTypeFromDrm(String path) {
if (!isDrmEnabled()) {
return 0;
@@ -1228,13 +1224,37 @@ public class MediaScanner
// always scan the file, so we can return the content://media Uri for existing files
return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),
- false, true);
+ false, true, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
return null;
}
}
+ public static boolean isNoMediaPath(String path) {
+ if (path == null) return false;
+
+ // return true if file or any parent directory has name starting with a dot
+ if (path.indexOf("/.") >= 0) return true;
+
+ // now check to see if any parent directories have a ".nomedia" file
+ // start from 1 so we don't bother checking in the root directory
+ int offset = 1;
+ while (offset >= 0) {
+ int slashIndex = path.indexOf('/', offset);
+ if (slashIndex > offset) {
+ slashIndex++; // move past slash
+ File file = new File(path.substring(0, slashIndex) + ".nomedia");
+ if (file.exists()) {
+ // we have a .nomedia in one of the parent directories
+ return true;
+ }
+ }
+ offset = slashIndex;
+ }
+ return false;
+ }
+
public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
initialize(volumeName);
MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
@@ -1279,7 +1299,7 @@ public class MediaScanner
// always scan the file, so we can return the content://media Uri for existing files
mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(),
- (format == MtpConstants.FORMAT_ASSOCIATION), true);
+ (format == MtpConstants.FORMAT_ASSOCIATION), true, isNoMediaPath(path));
}
} 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 ac326ef..b326671 100644
--- a/media/java/android/media/MediaScannerClient.java
+++ b/media/java/android/media/MediaScannerClient.java
@@ -21,9 +21,8 @@ package android.media;
*/
public interface MediaScannerClient
{
- public void scanFile(String path, long lastModified, long fileSize, boolean isDirectory);
-
- public void addNoMediaFolder(String path);
+ public void scanFile(String path, long lastModified, long fileSize,
+ boolean isDirectory, boolean noMedia);
/**
* Called by native code to return metadata extracted from media files.
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index a3dd136..9151799 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -67,7 +67,7 @@ public:
mScanFileMethodID = env->GetMethodID(
mediaScannerClientInterface,
"scanFile",
- "(Ljava/lang/String;JJZ)V");
+ "(Ljava/lang/String;JJZZ)V");
mHandleStringTagMethodID = env->GetMethodID(
mediaScannerClientInterface,
@@ -78,11 +78,6 @@ public:
mediaScannerClientInterface,
"setMimeType",
"(Ljava/lang/String;)V");
-
- mAddNoMediaFolderMethodID = env->GetMethodID(
- mediaScannerClientInterface,
- "addNoMediaFolder",
- "(Ljava/lang/String;)V");
}
}
@@ -95,7 +90,7 @@ 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, bool isDirectory)
+ long long fileSize, bool isDirectory, bool noMedia)
{
LOGV("scanFile: path(%s), time(%lld), size(%lld) and isDir(%d)",
path, lastModified, fileSize, isDirectory);
@@ -106,7 +101,7 @@ public:
}
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
- fileSize, isDirectory);
+ fileSize, isDirectory, noMedia);
mEnv->DeleteLocalRef(pathStr);
return (!mEnv->ExceptionCheck());
@@ -149,30 +144,12 @@ public:
return (!mEnv->ExceptionCheck());
}
- // Returns true if it succeeded, false if an exception occured
- // in the Java code
- virtual bool addNoMediaFolder(const char* path)
- {
- LOGV("addNoMediaFolder: path(%s)", path);
- jstring pathStr;
- if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
- return false;
- }
-
- mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
-
- mEnv->DeleteLocalRef(pathStr);
- return (!mEnv->ExceptionCheck());
- }
-
-
private:
JNIEnv *mEnv;
jobject mClient;
jmethodID mScanFileMethodID;
jmethodID mHandleStringTagMethodID;
jmethodID mSetMimeTypeMethodID;
- jmethodID mAddNoMediaFolderMethodID;
};
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 5ec573e..4e22175 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -70,8 +70,7 @@ status_t MediaScanner::processDirectory(
client.setLocale(locale());
status_t result =
- doProcessDirectory(
- pathBuffer, pathRemaining, client, exceptionCheck, exceptionEnv);
+ doProcessDirectory(pathBuffer, pathRemaining, client, false, exceptionCheck, exceptionEnv);
free(pathBuffer);
@@ -80,20 +79,18 @@ status_t MediaScanner::processDirectory(
status_t MediaScanner::doProcessDirectory(
char *path, int pathRemaining, MediaScannerClient &client,
- ExceptionCheck exceptionCheck, void *exceptionEnv) {
+ bool noMedia, ExceptionCheck exceptionCheck, void *exceptionEnv) {
// 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
+ // Treat all files as non-media in directories that contain a ".nomedia" file
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
strcpy(fileSpot, ".nomedia");
if (access(path, F_OK) == 0) {
- LOGD("found .nomedia, skipping directory\n");
- fileSpot[0] = 0;
- client.addNoMediaFolder(path);
- return OK;
+ LOGD("found .nomedia, setting noMedia flag\n");
+ noMedia = true;
}
// restore path
@@ -138,19 +135,20 @@ status_t MediaScanner::doProcessDirectory(
}
if (type == DT_REG || type == DT_DIR) {
if (type == DT_DIR) {
- // ignore directories with a name that starts with '.'
+ // set noMedia flag on directories with a name that starts with '.'
// for example, the Mac ".Trashes" directory
- if (name[0] == '.') continue;
+ if (name[0] == '.')
+ noMedia = true;
// report the directory to the client
if (stat(path, &statbuf) == 0) {
- client.scanFile(path, statbuf.st_mtime, 0, true);
+ client.scanFile(path, statbuf.st_mtime, 0, true, noMedia);
}
// and now process its contents
strcat(fileSpot, "/");
int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client,
- exceptionCheck, exceptionEnv);
+ noMedia, exceptionCheck, exceptionEnv);
if (err) {
// pass exceptions up - ignore other errors
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
@@ -159,7 +157,7 @@ status_t MediaScanner::doProcessDirectory(
}
} else {
stat(path, &statbuf);
- client.scanFile(path, statbuf.st_mtime, statbuf.st_size, false);
+ client.scanFile(path, statbuf.st_mtime, statbuf.st_size, false, noMedia);
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
}
}