summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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) {