diff options
-rw-r--r-- | core/java/android/provider/MediaStore.java | 12 | ||||
-rw-r--r-- | include/media/mediascanner.h | 8 | ||||
-rw-r--r-- | media/java/android/media/MediaFile.java | 49 | ||||
-rw-r--r-- | media/java/android/media/MediaScanner.java | 362 | ||||
-rw-r--r-- | media/java/android/media/MtpDatabase.java | 2 | ||||
-rw-r--r-- | media/jni/android_media_MediaScanner.cpp | 21 | ||||
-rw-r--r-- | media/libmedia/MediaScanner.cpp | 32 |
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) { |