summaryrefslogtreecommitdiffstats
path: root/media/java/android/media/MediaScanner.java
diff options
context:
space:
mode:
Diffstat (limited to 'media/java/android/media/MediaScanner.java')
-rw-r--r--media/java/android/media/MediaScanner.java176
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;