summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2010-09-10 14:47:36 -0400
committerMike Lockwood <lockwood@android.com>2010-09-12 23:21:44 -0400
commitc37255d5d0fd9e0ec02b0d7cb5c4b235e200d367 (patch)
tree6feb14e577a8ed66bf2c2afe6b39f47246b9cf49
parent6d000d4eb733fc6ad7fcd27a4022a41f8433306d (diff)
downloadframeworks_base-c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367.zip
frameworks_base-c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367.tar.gz
frameworks_base-c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367.tar.bz2
Media scanner support for tracking files of arbitrary type.
The native media scanner no longer filters files based on file extension. Audio, video, image and playlist files are handled as before, but non-media files are now inserted into the "files" table, which was originally added to support MTP. Change-Id: I9053218fb6d2671a3bb181405c34442b94678afc Signed-off-by: Mike Lockwood <lockwood@android.com>
-rw-r--r--core/java/android/provider/MediaStore.java12
-rw-r--r--include/media/mediascanner.h8
-rw-r--r--media/java/android/media/MediaFile.java49
-rw-r--r--media/java/android/media/MediaScanner.java362
-rw-r--r--media/java/android/media/MtpDatabase.java2
-rw-r--r--media/jni/android_media_MediaScanner.cpp21
-rw-r--r--media/libmedia/MediaScanner.cpp32
7 files changed, 247 insertions, 239 deletions
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index d3718f8..1417ef5 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -339,6 +339,18 @@ public final class MediaStore {
*/
public static final String MEDIA_ID = "media_id";
}
+
+ /**
+ * The MIME type of the file
+ * <P>Type: TEXT</P>
+ */
+ public static final String MIME_TYPE = "mime_type";
+
+ /**
+ * The title of the content
+ * <P>Type: TEXT</P>
+ */
+ public static final String TITLE = "title";
}
/**
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index 0d397ac..74c9d5d 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -38,8 +38,7 @@ struct MediaScanner {
typedef bool (*ExceptionCheck)(void* env);
virtual status_t processDirectory(
- const char *path, const char *extensions,
- MediaScannerClient &client,
+ const char *path, MediaScannerClient &client,
ExceptionCheck exceptionCheck, void *exceptionEnv);
void setLocale(const char *locale);
@@ -55,9 +54,8 @@ private:
char *mLocale;
status_t doProcessDirectory(
- char *path, int pathRemaining, const char *extensions,
- MediaScannerClient &client, ExceptionCheck exceptionCheck,
- void *exceptionEnv);
+ char *path, int pathRemaining, MediaScannerClient &client,
+ ExceptionCheck exceptionCheck, void *exceptionEnv);
MediaScanner(const MediaScanner &);
MediaScanner &operator=(const MediaScanner &);
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index fb2480e..bdb3c5c 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -34,8 +34,6 @@ import java.util.List;
* {@hide}
*/
public class MediaFile {
- // comma separated list of all file extensions supported by the media scanner
- public final static String sFileExtensions;
// Audio file types
public static final int FILE_TYPE_MP3 = 1;
@@ -191,54 +189,65 @@ public class MediaFile {
addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST);
addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", MtpConstants.FORMAT_WPL_PLAYLIST);
-
- // compute file extensions list for native Media Scanner
- StringBuilder builder = new StringBuilder();
- Iterator<String> iterator = sFileTypeMap.keySet().iterator();
-
- while (iterator.hasNext()) {
- if (builder.length() > 0) {
- builder.append(',');
- }
- builder.append(iterator.next());
- }
- sFileExtensions = builder.toString();
}
-
+
public static boolean isAudioFileType(int fileType) {
return ((fileType >= FIRST_AUDIO_FILE_TYPE &&
fileType <= LAST_AUDIO_FILE_TYPE) ||
(fileType >= FIRST_MIDI_FILE_TYPE &&
fileType <= LAST_MIDI_FILE_TYPE));
}
-
+
public static boolean isVideoFileType(int fileType) {
return (fileType >= FIRST_VIDEO_FILE_TYPE &&
fileType <= LAST_VIDEO_FILE_TYPE);
}
-
+
public static boolean isImageFileType(int fileType) {
return (fileType >= FIRST_IMAGE_FILE_TYPE &&
fileType <= LAST_IMAGE_FILE_TYPE);
}
-
+
public static boolean isPlayListFileType(int fileType) {
return (fileType >= FIRST_PLAYLIST_FILE_TYPE &&
fileType <= LAST_PLAYLIST_FILE_TYPE);
}
-
+
public static MediaFileType getFileType(String path) {
int lastDot = path.lastIndexOf(".");
if (lastDot < 0)
return null;
return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase());
}
-
+
+ // generates a title based on file name
+ public static String getFileTitle(String path) {
+ // extract file name after last slash
+ int lastSlash = path.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ lastSlash++;
+ if (lastSlash < path.length()) {
+ path = path.substring(lastSlash);
+ }
+ }
+ // truncate the file extension (if any)
+ int lastDot = path.lastIndexOf('.');
+ if (lastDot > 0) {
+ path = path.substring(0, lastDot);
+ }
+ return path;
+ }
+
public static int getFileTypeForMimeType(String mimeType) {
Integer value = sMimeTypeMap.get(mimeType);
return (value == null ? 0 : value.intValue());
}
+ public static String getMimeTypeForFile(String path) {
+ MediaFileType mediaFileType = getFileType(path);
+ return (mediaFileType == null ? null : mediaFileType.mimeType);
+ }
+
public static int getFormatCode(String fileName, String mimeType) {
if (mimeType != null) {
Integer value = sMimeTypeToFormatMap.get(mimeType);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 8ca6237..9f2a49c 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -34,6 +34,7 @@ import android.os.SystemProperties;
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.MediaStore.Audio;
+import android.provider.MediaStore.Files;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
import android.provider.MediaStore.Audio.Genres;
@@ -109,41 +110,15 @@ public class MediaScanner
private final static String TAG = "MediaScanner";
- private static final String[] AUDIO_PROJECTION = new String[] {
- Audio.Media._ID, // 0
- Audio.Media.DATA, // 1
- Audio.Media.DATE_MODIFIED, // 2
+ private static final String[] PRESCAN_PROJECTION = new String[] {
+ Files.FileColumns._ID, // 0
+ Files.FileColumns.DATA, // 1
+ Files.FileColumns.DATE_MODIFIED, // 2
};
- private static final int ID_AUDIO_COLUMN_INDEX = 0;
- private static final int PATH_AUDIO_COLUMN_INDEX = 1;
- private static final int DATE_MODIFIED_AUDIO_COLUMN_INDEX = 2;
-
- private static final String[] VIDEO_PROJECTION = new String[] {
- Video.Media._ID, // 0
- Video.Media.DATA, // 1
- Video.Media.DATE_MODIFIED, // 2
- };
-
- private static final int ID_VIDEO_COLUMN_INDEX = 0;
- private static final int PATH_VIDEO_COLUMN_INDEX = 1;
- private static final int DATE_MODIFIED_VIDEO_COLUMN_INDEX = 2;
-
- private static final String[] IMAGES_PROJECTION = new String[] {
- Images.Media._ID, // 0
- Images.Media.DATA, // 1
- Images.Media.DATE_MODIFIED, // 2
- };
-
- private static final int ID_IMAGES_COLUMN_INDEX = 0;
- private static final int PATH_IMAGES_COLUMN_INDEX = 1;
- private static final int DATE_MODIFIED_IMAGES_COLUMN_INDEX = 2;
-
- private static final String[] PLAYLISTS_PROJECTION = new String[] {
- Audio.Playlists._ID, // 0
- Audio.Playlists.DATA, // 1
- Audio.Playlists.DATE_MODIFIED, // 2
- };
+ private static final int PRESCAN_ID_COLUMN_INDEX = 0;
+ private static final int PRESCAN_PATH_COLUMN_INDEX = 1;
+ private static final int PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 2;
private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] {
Audio.Playlists.Members.PLAYLIST_ID, // 0
@@ -304,6 +279,7 @@ public class MediaScanner
private Uri mThumbsUri;
private Uri mGenresUri;
private Uri mPlaylistsUri;
+ private Uri mFilesUri;
private boolean mProcessPlaylists, mProcessGenres;
private int mMtpObjectHandle;
@@ -354,7 +330,7 @@ public class MediaScanner
@Override
public String toString() {
- return mPath;
+ return mPath + " mTableUri: " + mTableUri + " mRowId: " + mRowId;
}
}
@@ -432,6 +408,9 @@ public class MediaScanner
}
mMimeType = null;
+ mFileType = 0;
+ mFileSize = fileSize;
+
// try mimeType first, if it is specified
if (mimeType != null) {
mFileType = MediaFile.getFileTypeForMimeType(mimeType);
@@ -439,7 +418,6 @@ public class MediaScanner
mMimeType = mimeType;
}
}
- mFileSize = fileSize;
// if mimeType was not specified, compute file type based on file extension.
if (mMimeType == null) {
@@ -456,7 +434,17 @@ public class MediaScanner
}
FileCacheEntry entry = mFileCache.get(key);
if (entry == null) {
- entry = new FileCacheEntry(null, 0, path, 0);
+ Uri tableUri;
+ if (MediaFile.isVideoFileType(mFileType)) {
+ tableUri = mVideoUri;
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ tableUri = mImagesUri;
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ tableUri = mAudioUri;
+ } else {
+ tableUri = mFilesUri;
+ }
+ entry = new FileCacheEntry(tableUri, 0, path, 0);
mFileCache.put(key, entry);
}
entry.mSeenInFileSystem = true;
@@ -501,7 +489,8 @@ public class MediaScanner
doScanFile(path, mimeType, lastModified, fileSize, false);
}
- public Uri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) {
+ public Uri doScanFile(String path, String mimeType, long lastModified,
+ long fileSize, boolean scanAlways) {
Uri result = null;
// long t1 = System.currentTimeMillis();
try {
@@ -516,7 +505,9 @@ public class MediaScanner
boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
(!ringtones && !notifications && !alarms && !podcasts);
- if (!MediaFile.isImageFileType(mFileType)) {
+ // we only extract metadata for audio and video files
+ if (MediaFile.isAudioFileType(mFileType)
+ || MediaFile.isVideoFileType(mFileType)) {
processFile(path, mimeType, this);
}
@@ -627,9 +618,6 @@ public class MediaScanner
map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified);
map.put(MediaStore.MediaColumns.SIZE, mFileSize);
map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
- if (mMtpObjectHandle != 0) {
- map.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
- }
if (MediaFile.isVideoFileType(mFileType)) {
map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING));
@@ -659,21 +647,6 @@ public class MediaScanner
boolean alarms, boolean music, boolean podcasts)
throws RemoteException {
// update database
- Uri tableUri;
- boolean isAudio = MediaFile.isAudioFileType(mFileType);
- boolean isVideo = MediaFile.isVideoFileType(mFileType);
- boolean isImage = MediaFile.isImageFileType(mFileType);
- if (isVideo) {
- tableUri = mVideoUri;
- } else if (isImage) {
- tableUri = mImagesUri;
- } else if (isAudio) {
- tableUri = mAudioUri;
- } else {
- // don't add file to database if not audio, video or image
- return null;
- }
- entry.mTableUri = tableUri;
// use album artist if artist is missing
if (mArtist == null || mArtist.length() == 0) {
@@ -683,20 +656,7 @@ public class MediaScanner
ContentValues values = toValues();
String title = values.getAsString(MediaStore.MediaColumns.TITLE);
if (title == null || TextUtils.isEmpty(title.trim())) {
- title = values.getAsString(MediaStore.MediaColumns.DATA);
- // extract file name after last slash
- int lastSlash = title.lastIndexOf('/');
- if (lastSlash >= 0) {
- lastSlash++;
- if (lastSlash < title.length()) {
- title = title.substring(lastSlash);
- }
- }
- // truncate the file extension (if any)
- int lastDot = title.lastIndexOf('.');
- if (lastDot > 0) {
- title = title.substring(0, lastDot);
- }
+ title = MediaFile.getFileTitle(values.getAsString(MediaStore.MediaColumns.DATA));
values.put(MediaStore.MediaColumns.TITLE, title);
}
String album = values.getAsString(Audio.Media.ALBUM);
@@ -720,7 +680,7 @@ public class MediaScanner
}
}
long rowId = entry.mRowId;
- if (isAudio && rowId == 0) {
+ if (MediaFile.isAudioFileType(mFileType) && rowId == 0) {
// Only set these for new entries. For existing entries, they
// may have been modified later, and we want to keep the current
// values so that custom ringtones still show up in the ringtone
@@ -773,8 +733,15 @@ public class MediaScanner
}
}
+ Uri tableUri = entry.mTableUri;
Uri result = null;
if (rowId == 0) {
+ if (mMtpObjectHandle != 0) {
+ values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
+ }
+ if (tableUri == mFilesUri) {
+ values.put(Files.FileColumns.FORMAT, MediaFile.getFormatCode(entry.mPath, mMimeType));
+ }
// new file, insert it
result = mMediaProvider.insert(tableUri, values);
if (result != null) {
@@ -890,7 +857,7 @@ public class MediaScanner
}; // end of anonymous MediaScannerClient instance
- private void prescan(String filePath) throws RemoteException {
+ private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
Cursor c = null;
String where = null;
String[] selectionArgs = null;
@@ -906,21 +873,24 @@ public class MediaScanner
mPlayLists.clear();
}
+ if (filePath != null) {
+ // query for only one file
+ where = Files.FileColumns.DATA + "=?";
+ selectionArgs = new String[] { filePath };
+ }
+
// Build the list of files from the content provider
try {
- // Read existing files from the audio table
- if (filePath != null) {
- where = MediaStore.Audio.Media.DATA + "=?";
- selectionArgs = new String[] { filePath };
- }
- c = mMediaProvider.query(mAudioUri, AUDIO_PROJECTION, where, selectionArgs, null);
+ if (prescanFiles) {
+ // First read existing files from the files table
- if (c != null) {
- try {
+ c = mMediaProvider.query(mFilesUri, PRESCAN_PROJECTION, where, selectionArgs, null);
+
+ if (c != null) {
while (c.moveToNext()) {
- long rowId = c.getLong(ID_AUDIO_COLUMN_INDEX);
- String path = c.getString(PATH_AUDIO_COLUMN_INDEX);
- long lastModified = c.getLong(DATE_MODIFIED_AUDIO_COLUMN_INDEX);
+ long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
+ String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
+ long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
// Only consider entries with absolute path names.
// This allows storing URIs in the database without the
@@ -930,114 +900,141 @@ public class MediaScanner
if (mCaseInsensitivePaths) {
key = path.toLowerCase();
}
- mFileCache.put(key, new FileCacheEntry(mAudioUri, rowId, path,
- lastModified));
+
+ FileCacheEntry entry = new FileCacheEntry(mFilesUri, rowId, path,
+ lastModified);
+ mFileCache.put(key, entry);
}
}
- } finally {
c.close();
c = null;
}
}
- // Read existing files from the video table
- if (filePath != null) {
- where = MediaStore.Video.Media.DATA + "=?";
- } else {
- where = null;
+ // Read existing files from the audio table and update FileCacheEntry
+ c = mMediaProvider.query(mAudioUri, PRESCAN_PROJECTION, where, selectionArgs, null);
+ if (c != null) {
+ while (c.moveToNext()) {
+ long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
+ String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
+ long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+
+ // Only consider entries with absolute path names.
+ // This allows storing URIs in the database without the
+ // media scanner removing them.
+ if (path.startsWith("/")) {
+ String key = path;
+ if (mCaseInsensitivePaths) {
+ key = path.toLowerCase();
+ }
+ FileCacheEntry entry = mFileCache.get(path);
+ if (entry == null) {
+ mFileCache.put(key, new FileCacheEntry(mAudioUri, rowId, path,
+ lastModified));
+ } else {
+ // update the entry
+ entry.mTableUri = mAudioUri;
+ entry.mRowId = rowId;
+ }
+ }
+ }
+ c.close();
+ c = null;
}
- c = mMediaProvider.query(mVideoUri, VIDEO_PROJECTION, where, selectionArgs, null);
+ // Read existing files from the video table and update FileCacheEntry
+ c = mMediaProvider.query(mVideoUri, PRESCAN_PROJECTION, where, selectionArgs, null);
if (c != null) {
- try {
- while (c.moveToNext()) {
- long rowId = c.getLong(ID_VIDEO_COLUMN_INDEX);
- String path = c.getString(PATH_VIDEO_COLUMN_INDEX);
- long lastModified = c.getLong(DATE_MODIFIED_VIDEO_COLUMN_INDEX);
-
- // Only consider entries with absolute path names.
- // This allows storing URIs in the database without the
- // media scanner removing them.
- if (path.startsWith("/")) {
- String key = path;
- if (mCaseInsensitivePaths) {
- key = path.toLowerCase();
- }
+ while (c.moveToNext()) {
+ long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
+ String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
+ long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+
+ // Only consider entries with absolute path names.
+ // This allows storing URIs in the database without the
+ // media scanner removing them.
+ if (path.startsWith("/")) {
+ String key = path;
+ if (mCaseInsensitivePaths) {
+ key = path.toLowerCase();
+ }
+ FileCacheEntry entry = mFileCache.get(path);
+ if (entry == null) {
mFileCache.put(key, new FileCacheEntry(mVideoUri, rowId, path,
lastModified));
+ } else {
+ // update the entry
+ entry.mTableUri = mVideoUri;
+ entry.mRowId = rowId;
}
}
- } finally {
- c.close();
- c = null;
}
+ c.close();
+ c = null;
}
- // Read existing files from the images table
- if (filePath != null) {
- where = MediaStore.Images.Media.DATA + "=?";
- } else {
- where = null;
- }
- mOriginalCount = 0;
- c = mMediaProvider.query(mImagesUri, IMAGES_PROJECTION, where, selectionArgs, null);
-
+ // Read existing files from the video table and update FileCacheEntry
+ c = mMediaProvider.query(mImagesUri, PRESCAN_PROJECTION, where, selectionArgs, null);
if (c != null) {
- try {
- mOriginalCount = c.getCount();
- while (c.moveToNext()) {
- long rowId = c.getLong(ID_IMAGES_COLUMN_INDEX);
- String path = c.getString(PATH_IMAGES_COLUMN_INDEX);
- long lastModified = c.getLong(DATE_MODIFIED_IMAGES_COLUMN_INDEX);
-
- // Only consider entries with absolute path names.
- // This allows storing URIs in the database without the
- // media scanner removing them.
- if (path.startsWith("/")) {
- String key = path;
- if (mCaseInsensitivePaths) {
- key = path.toLowerCase();
- }
- mFileCache.put(key, new FileCacheEntry(mImagesUri, rowId, path,
- lastModified));
- }
+ while (c.moveToNext()) {
+ long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
+ String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
+ long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+
+ // Only consider entries with absolute path names.
+ // This allows storing URIs in the database without the
+ // media scanner removing them.
+ if (path.startsWith("/")) {
+ String key = path;
+ if (mCaseInsensitivePaths) {
+ key = path.toLowerCase();
+ }
+ FileCacheEntry entry = mFileCache.get(path);
+ if (entry == null) {
+ mFileCache.put(key, new FileCacheEntry(mImagesUri, rowId, path,
+ lastModified));
+ } else {
+ // update the entry
+ entry.mTableUri = mImagesUri;
+ entry.mRowId = rowId;
+ }
}
- } finally {
- c.close();
- c = null;
}
+ c.close();
+ c = null;
}
if (mProcessPlaylists) {
- // Read existing files from the playlists table
- if (filePath != null) {
- where = MediaStore.Audio.Playlists.DATA + "=?";
- } else {
- where = null;
- }
- c = mMediaProvider.query(mPlaylistsUri, PLAYLISTS_PROJECTION, where, selectionArgs, null);
-
+ // Read existing files from the playlists table and update FileCacheEntry
+ c = mMediaProvider.query(mPlaylistsUri, PRESCAN_PROJECTION, where,
+ selectionArgs, null);
if (c != null) {
- try {
- while (c.moveToNext()) {
- String path = c.getString(PATH_PLAYLISTS_COLUMN_INDEX);
-
- if (path != null && path.length() > 0) {
- long rowId = c.getLong(ID_PLAYLISTS_COLUMN_INDEX);
- long lastModified = c.getLong(DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX);
+ while (c.moveToNext()) {
+ long rowId = c.getLong(PRESCAN_ID_COLUMN_INDEX);
+ String path = c.getString(PRESCAN_PATH_COLUMN_INDEX);
+ long lastModified = c.getLong(PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
- String key = path;
- if (mCaseInsensitivePaths) {
- key = path.toLowerCase();
- }
+ // Only consider entries with absolute path names.
+ // This allows storing URIs in the database without the
+ // media scanner removing them.
+ if (path.startsWith("/")) {
+ String key = path;
+ if (mCaseInsensitivePaths) {
+ key = path.toLowerCase();
+ }
+ FileCacheEntry entry = mFileCache.get(path);
+ if (entry == null) {
mFileCache.put(key, new FileCacheEntry(mPlaylistsUri, rowId, path,
lastModified));
+ } else {
+ // update the entry
+ entry.mTableUri = mPlaylistsUri;
+ entry.mRowId = rowId;
}
}
- } finally {
- c.close();
- c = null;
}
+ c.close();
+ c = null;
}
}
}
@@ -1139,7 +1136,7 @@ public class MediaScanner
values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, 0);
mMediaProvider.update(ContentUris.withAppendedId(mPlaylistsUri, entry.mRowId), values, null, null);
} else {
- mMediaProvider.delete(ContentUris.withAppendedId(entry.mTableUri, entry.mRowId), null, null);
+ mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId), null, null);
iterator.remove();
}
}
@@ -1167,6 +1164,7 @@ public class MediaScanner
mVideoUri = Video.Media.getContentUri(volumeName);
mImagesUri = Images.Media.getContentUri(volumeName);
mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
+ mFilesUri = Files.getContentUri(volumeName);
if (!volumeName.equals("internal")) {
// we only support playlists on external media
@@ -1189,11 +1187,11 @@ public class MediaScanner
try {
long start = System.currentTimeMillis();
initialize(volumeName);
- prescan(null);
+ prescan(null, true);
long prescan = System.currentTimeMillis();
for (int i = 0; i < directories.length; i++) {
- processDirectory(directories[i], MediaFile.sFileExtensions, mClient);
+ processDirectory(directories[i], mClient);
}
long scan = System.currentTimeMillis();
postscan(directories);
@@ -1220,7 +1218,7 @@ public class MediaScanner
public Uri scanSingleFile(String path, String volumeName, String mimeType) {
try {
initialize(volumeName);
- prescan(path);
+ prescan(path, true);
File file = new File(path);
@@ -1235,12 +1233,34 @@ public class MediaScanner
}
}
- public Uri scanMtpFile(String path, String volumeName, int objectHandle, int format) {
- String mimeType = MediaFile.getMimeTypeForFormatCode(format);
+ public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
+ MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
+ int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
+
+ if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) &&
+ !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType)) {
+ // nothing to do
+ return;
+ }
+
mMtpObjectHandle = objectHandle;
- Uri result = scanSingleFile(path, volumeName, mimeType);
- mMtpObjectHandle = 0;
- return result;
+ try {
+ initialize(volumeName);
+ // MTP will create a file entry for us so we don't want to do it in prescan
+ prescan(path, false);
+
+ File file = new File(path);
+
+ // lastModified is in milliseconds on Files.
+ 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);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
+ } finally {
+ mMtpObjectHandle = 0;
+ }
}
// returns the number of matching file/directory names, starting from the right
@@ -1522,7 +1542,7 @@ public class MediaScanner
}
}
- private native void processDirectory(String path, String extensions, MediaScannerClient client);
+ private native void processDirectory(String path, MediaScannerClient client);
private native void processFile(String path, String mimeType, MediaScannerClient client);
public native void setLocale(String locale);
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index ad029a6..6b0b761 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -170,7 +170,7 @@ public class MtpDatabase {
Log.e(TAG, "RemoteException in endSendObject", e);
}
} else {
- Uri uri = mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
+ mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
}
} else {
deleteFile(handle);
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 273f1af..fd0b233 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -146,7 +146,7 @@ static bool ExceptionCheck(void* env)
}
static void
-android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jstring extensions, jobject client)
+android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jobject client)
{
MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
@@ -154,27 +154,16 @@ android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring p
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
- if (extensions == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
-
+
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr == NULL) { // Out of memory
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
- const char *extensionsStr = env->GetStringUTFChars(extensions, NULL);
- if (extensionsStr == NULL) { // Out of memory
- env->ReleaseStringUTFChars(path, pathStr);
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
- return;
- }
MyMediaScannerClient myClient(env, client);
- mp->processDirectory(pathStr, extensionsStr, myClient, ExceptionCheck, env);
+ mp->processDirectory(pathStr, myClient, ExceptionCheck, env);
env->ReleaseStringUTFChars(path, pathStr);
- env->ReleaseStringUTFChars(extensions, extensionsStr);
}
static void
@@ -309,9 +298,9 @@ android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"processDirectory", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
+ {"processDirectory", "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
(void *)android_media_MediaScanner_processDirectory},
- {"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
+ {"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
(void *)android_media_MediaScanner_processFile},
{"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale},
{"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt},
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index ba98f04..c31b622 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -48,8 +48,7 @@ const char *MediaScanner::locale() const {
}
status_t MediaScanner::processDirectory(
- const char *path, const char *extensions,
- MediaScannerClient &client,
+ const char *path, MediaScannerClient &client,
ExceptionCheck exceptionCheck, void *exceptionEnv) {
int pathLength = strlen(path);
if (pathLength >= PATH_MAX) {
@@ -72,35 +71,16 @@ status_t MediaScanner::processDirectory(
status_t result =
doProcessDirectory(
- pathBuffer, pathRemaining, extensions, client,
- exceptionCheck, exceptionEnv);
+ pathBuffer, pathRemaining, client, exceptionCheck, exceptionEnv);
free(pathBuffer);
return result;
}
-static bool fileMatchesExtension(const char* path, const char* extensions) {
- const char* extension = strrchr(path, '.');
- if (!extension) return false;
- ++extension; // skip the dot
- if (extension[0] == 0) return false;
-
- while (extensions[0]) {
- const char* comma = strchr(extensions, ',');
- size_t length = (comma ? comma - extensions : strlen(extensions));
- if (length == strlen(extension) && strncasecmp(extension, extensions, length) == 0) return true;
- extensions += length;
- if (extensions[0] == ',') ++extensions;
- }
-
- return false;
-}
-
status_t MediaScanner::doProcessDirectory(
- char *path, int pathRemaining, const char *extensions,
- MediaScannerClient &client, ExceptionCheck exceptionCheck,
- void *exceptionEnv) {
+ char *path, int pathRemaining, MediaScannerClient &client,
+ ExceptionCheck exceptionCheck, void *exceptionEnv) {
// place to copy file or directory name
char* fileSpot = path + strlen(path);
struct dirent* entry;
@@ -163,14 +143,14 @@ status_t MediaScanner::doProcessDirectory(
if (name[0] == '.') continue;
strcat(fileSpot, "/");
- int err = doProcessDirectory(path, pathRemaining - nameLength - 1, extensions, 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;
LOGE("Error processing '%s' - skipping\n", path);
continue;
}
- } else if (fileMatchesExtension(path, extensions)) {
+ } else {
struct stat statbuf;
stat(path, &statbuf);
if (statbuf.st_size > 0) {