diff options
Diffstat (limited to 'media/java/android/media/MediaScanner.java')
-rw-r--r-- | media/java/android/media/MediaScanner.java | 176 |
1 files changed, 139 insertions, 37 deletions
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 9ea6722..9264bc0 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -20,6 +20,7 @@ import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; +import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; @@ -41,11 +42,13 @@ import android.provider.MediaStore.Files.FileColumns; import android.provider.MediaStore.Images; import android.provider.MediaStore.Video; import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.sax.Element; import android.sax.ElementListener; import android.sax.RootElement; import android.system.ErrnoException; import android.system.Os; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.util.Xml; @@ -61,6 +64,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Internal service helper that no-one should use directly. @@ -324,26 +329,27 @@ public class MediaScanner // used when scanning the image database so we know whether we have to prune // old thumbnail files private int mOriginalCount; - /** Whether the database had any entries in it before the scan started */ - private boolean mWasEmptyPriorToScan = false; /** Whether the scanner has set a default sound for the ringer ringtone. */ - private boolean mDefaultRingtoneSet; + private boolean[] mDefaultRingtonesSet; /** Whether the scanner has set a default sound for the notification ringtone. */ private boolean mDefaultNotificationSet; /** Whether the scanner has set a default sound for the alarm ringtone. */ private boolean mDefaultAlarmSet; - /** The filename for the default sound for the ringer ringtone. */ - private String mDefaultRingtoneFilename; + /** The filenames for the default sound for the ringer ringtone. */ + private String[] mDefaultRingtoneFilenames; /** The filename for the default sound for the notification ringtone. */ private String mDefaultNotificationFilename; /** The filename for the default sound for the alarm ringtone. */ private String mDefaultAlarmAlertFilename; + /** The number of phones in the system */ + private int mPhoneCount = -1; /** * The prefix for system properties that define the default sound for * ringtones. Concatenate the name of the setting from Settings * to get the full system property. */ private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config."; + private static final int DEFAULT_SIM_INDEX = 0; // set to true if file path comparisons should be case insensitive. // this should be set when scanning files on a case insensitive file system. @@ -351,6 +357,11 @@ public class MediaScanner private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); + // For basic VorbisComment DATE tag support. It can take two forms, YYYY + // or YYYY-MM. This pattern is used to extract the year for compatibility + // with the ID3 YEAR tag. + private static final Pattern DATE_YEAR_DETECT_PATTERN = Pattern.compile("^(\\d{4})(-\\d{2})?$"); + private static class FileEntry { long mRowId; String mPath; @@ -401,8 +412,21 @@ public class MediaScanner } private void setDefaultRingtoneFileNames() { - mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX + String defaultAllSimRingtone = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX + Settings.System.RINGTONE); + + mPhoneCount = TelephonyManager.getDefault().getPhoneCount(); + mDefaultRingtoneFilenames = new String[mPhoneCount]; + mDefaultRingtonesSet = new boolean[mPhoneCount]; + + mDefaultRingtoneFilenames[DEFAULT_SIM_INDEX] = defaultAllSimRingtone; + + for (int i = (DEFAULT_SIM_INDEX + 1); i < mPhoneCount; i++) { + String defaultIterSimRingtone = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX + + Settings.System.RINGTONE + "_" + (i + 1), defaultAllSimRingtone); + mDefaultRingtoneFilenames[i] = defaultIterSimRingtone; + } + mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX + Settings.System.NOTIFICATION_SOUND); mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX @@ -529,12 +553,30 @@ public class MediaScanner FileEntry entry = beginFile(path, mimeType, lastModified, fileSize, isDirectory, noMedia); + if (entry == null) { + return null; + } + // if this file was just inserted via mtp, set the rowid to zero // (even though it already exists in the database), to trigger // the correct code path for updating its entry if (mMtpObjectHandle != 0) { entry.mRowId = 0; } + + if (entry.mPath != null && + ((!mDefaultNotificationSet && + doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) + || (mPhoneCount > 0 && !mDefaultRingtonesSet[(mPhoneCount-1)] && + doesPathHaveFilename(entry.mPath, + mDefaultRingtoneFilenames[(mPhoneCount-1)])) + || (!mDefaultAlarmSet && + doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)))) { + Log.w(TAG, "forcing rescan of " + entry.mPath + + "since ringtone setting didn't finish"); + scanAlways = true; + } + // rescan for metadata if file was modified since last scan if (entry != null && (entry.mLastModifiedChanged || scanAlways)) { if (noMedia) { @@ -615,6 +657,13 @@ public class MediaScanner mGenre = getGenreName(value); } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) { mYear = parseSubstring(value, 0, 0); + } else if (mYear == 0 && name.equalsIgnoreCase("date") || name.startsWith("date;")) { + // Since Android doesn't support DATE tag itself, just use it to extract + // the year, if the YEAR tag isn't present. + Matcher m = DATE_YEAR_DETECT_PATTERN.matcher(value); + if (m.find()) { + mYear = parseSubstring(m.group(1), 0, 0); + } } else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) { // track number might be of the form "2/12" // we just read the number before the slash @@ -914,6 +963,30 @@ public class MediaScanner } Uri result = null; boolean needToSetSettings = false; + // Setting a flag in order not to use bulk insert for the file related with + // notifications, ringtones, and alarms, because the rowId of the inserted file is + // needed. + if (notifications && !mDefaultNotificationSet) { + if (TextUtils.isEmpty(mDefaultNotificationFilename) || + doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { + needToSetSettings = true; + } + } else if (ringtones && !ringtoneDefaultsSet()) { + for (int i = 0; i < mPhoneCount; i++) { + // Check if ringtone matches default ringtone + if (TextUtils.isEmpty(mDefaultRingtoneFilenames[i]) || + doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilenames[i])) { + needToSetSettings = true; + break; + } + } + } else if (alarms && !mDefaultAlarmSet) { + if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || + doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { + needToSetSettings = true; + } + } + if (rowId == 0) { if (mMtpObjectHandle != 0) { values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle); @@ -925,28 +998,6 @@ public class MediaScanner } values.put(Files.FileColumns.FORMAT, format); } - // Setting a flag in order not to use bulk insert for the file related with - // notifications, ringtones, and alarms, because the rowId of the inserted file is - // needed. - if (mWasEmptyPriorToScan) { - if (notifications && !mDefaultNotificationSet) { - if (TextUtils.isEmpty(mDefaultNotificationFilename) || - doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { - needToSetSettings = true; - } - } else if (ringtones && !mDefaultRingtoneSet) { - if (TextUtils.isEmpty(mDefaultRingtoneFilename) || - doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { - needToSetSettings = true; - } - } else if (alarms && !mDefaultAlarmSet) { - if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || - doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { - needToSetSettings = true; - } - } - } - // New file, insert it. // Directories need to be inserted before the files they contain, so they // get priority when bulk inserting. @@ -996,8 +1047,27 @@ public class MediaScanner setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); mDefaultNotificationSet = true; } else if (ringtones) { - setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId); - mDefaultRingtoneSet = true; + String uri = null; + for (int i = 0; i < mPhoneCount; i++) { + if (mDefaultRingtonesSet[i]) { + continue; + } + // Check if ringtone matches default ringtone + if (!TextUtils.isEmpty(mDefaultRingtoneFilenames[i]) && + !doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilenames[i])) { + continue; + } + if (i == DEFAULT_SIM_INDEX) { + uri = Settings.System.RINGTONE; + } else { + uri = Settings.System.RINGTONE + "_" + (i + 1); + } + + // Set default ringtone + setSettingIfNotSet(uri, tableUri, rowId); + + mDefaultRingtonesSet[i] = true; + } } else if (alarms) { setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId); mDefaultAlarmSet = true; @@ -1007,6 +1077,15 @@ public class MediaScanner return result; } + private boolean ringtoneDefaultsSet() { + for (boolean defaultSet : mDefaultRingtonesSet) { + if (!defaultSet) { + return false; + } + } + return true; + } + private boolean doesPathHaveFilename(String path, String filename) { int pathFilenameStart = path.lastIndexOf(File.separatorChar) + 1; int filenameLength = filename.length(); @@ -1016,14 +1095,18 @@ public class MediaScanner private void setSettingIfNotSet(String settingName, Uri uri, long rowId) { - String existingSettingValue = Settings.System.getString(mContext.getContentResolver(), - settingName); + if(wasSettingAlreadySet(settingName)) { + return; + } + ContentResolver cr = mContext.getContentResolver(); + String existingSettingValue = Settings.System.getString(cr, settingName); if (TextUtils.isEmpty(existingSettingValue)) { // Set the setting to the given URI - Settings.System.putString(mContext.getContentResolver(), settingName, + Settings.System.putString(cr, settingName, ContentUris.withAppendedId(uri, rowId).toString()); } + Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1); } private int getFileTypeFromDrm(String path) { @@ -1050,6 +1133,20 @@ public class MediaScanner }; // end of anonymous MediaScannerClient instance + private String settingSetIndicatorName(String base) { + return base + "_set"; + } + + private boolean wasSettingAlreadySet(String name) { + ContentResolver cr = mContext.getContentResolver(); + String indicatorName = settingSetIndicatorName(name); + try { + return Settings.System.getInt(cr, indicatorName) != 0; + } catch (SettingNotFoundException e) { + return false; + } + } + private void prescan(String filePath, boolean prescanFiles) throws RemoteException { Cursor c = null; String where = null; @@ -1071,6 +1168,13 @@ public class MediaScanner selectionArgs = new String[] { "" }; } + mDefaultRingtonesSet[0] = wasSettingAlreadySet(Settings.System.RINGTONE); + for (int i=1; i< mPhoneCount; i++) { + mDefaultRingtonesSet[i] = wasSettingAlreadySet(Settings.System.RINGTONE + "_" + i); + } + mDefaultNotificationSet = wasSettingAlreadySet(Settings.System.NOTIFICATION_SOUND); + mDefaultAlarmSet = wasSettingAlreadySet(Settings.System.ALARM_ALERT); + // Tell the provider to not delete the file. // If the file is truly gone the delete is unnecessary, and we want to avoid // accidentally deleting files that are really there (this may happen if the @@ -1089,7 +1193,6 @@ public class MediaScanner // with CursorWindow positioning. long lastId = Long.MIN_VALUE; Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build(); - mWasEmptyPriorToScan = true; while (true) { selectionArgs[0] = "" + lastId; @@ -1108,7 +1211,6 @@ public class MediaScanner if (num == 0) { break; } - mWasEmptyPriorToScan = false; while (c.moveToNext()) { long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX); @@ -1260,7 +1362,7 @@ public class MediaScanner } } - private void postscan(String[] directories) throws RemoteException { + private void postscan(final String[] directories) throws RemoteException { // handle playlists last, after we know what media files are on the storage. if (mProcessPlaylists) { @@ -1364,7 +1466,7 @@ 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, MediaScanner.isNoMediaPath(path)); + file.isDirectory(), true, MediaScanner.isNoMediaPath(path)); } catch (RemoteException e) { Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); return null; |