Merge "Fix bug #6522190 MountService should respond to configuration changes ("INTERNAL STORAGE" string should be translated dynamically)" into jb-dev
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 266233a..1e17a97 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -19,7 +19,7 @@
import static android.Manifest.permission.ACCESS_CACHE_FILESYSTEM;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
import android.app.SearchManager;
@@ -2717,7 +2717,10 @@
// case insensitive match when looking for parent directory.
// TODO: investigate whether a "nocase" constraint on the column and
// using "=" would give the same result faster.
- String selection = (mCaseInsensitivePaths ? MediaStore.MediaColumns.DATA + " LIKE ?"
+ String selection = (mCaseInsensitivePaths ? MediaStore.MediaColumns.DATA + " LIKE ?1"
+ // The like above makes it use the index.
+ // The comparison below makes it correct when the path has wildcard chars
+ + " AND lower(_data)=lower(?1)"
// search only directories.
+ " AND format=" + MtpConstants.FORMAT_ASSOCIATION
: MediaStore.MediaColumns.DATA + "=?");
@@ -2731,6 +2734,9 @@
id = insertDirectory(helper, db, parentPath);
if (LOCAL_LOGV) Log.v(TAG, "Inserted " + parentPath);
} else {
+ if (c.getCount() > 1) {
+ Log.e(TAG, "more than one match for " + parentPath);
+ }
c.moveToFirst();
id = c.getLong(0);
if (LOCAL_LOGV) Log.v(TAG, "Queried " + parentPath);
@@ -3373,21 +3379,43 @@
*
* @param path The path to the new .nomedia file or hidden directory
*/
- private void processNewNoMediaPath(DatabaseHelper helper, SQLiteDatabase db, String path) {
- File nomedia = new File(path);
+ private void processNewNoMediaPath(final DatabaseHelper helper, final SQLiteDatabase db,
+ final String path) {
+ final File nomedia = new File(path);
if (nomedia.exists()) {
- // only do this if the file actually exists, so we don't get tricked
- // by someone just inserting a .nomedia entry into the database
- String hiddenroot = nomedia.isDirectory() ? path : nomedia.getParent();
- ContentValues mediatype = new ContentValues();
- mediatype.put("media_type", 0);
- int numrows = db.update("files", mediatype, "_data LIKE ?", new String[] { hiddenroot + "/%"});
- helper.mNumUpdates += numrows;
- ContentResolver res = getContext().getContentResolver();
- res.notifyChange(Uri.parse("content://media/"), null);
+ hidePath(helper, db, path);
+ } else {
+ // File doesn't exist. Try again in a little while.
+ // XXX there's probably a better way of doing this
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ SystemClock.sleep(2000);
+ if (nomedia.exists()) {
+ hidePath(helper, db, path);
+ } else {
+ Log.w(TAG, "does not exist: " + path, new Exception());
+ }
+ }}).start();
}
}
+ private void hidePath(DatabaseHelper helper, SQLiteDatabase db, String path) {
+ File nomedia = new File(path);
+ String hiddenroot = nomedia.isDirectory() ? path : nomedia.getParent();
+ ContentValues mediatype = new ContentValues();
+ mediatype.put("media_type", 0);
+ int numrows = db.update("files", mediatype,
+ // the "like" test makes use of the index, while the lower() test ensures it
+ // doesn't match entries it shouldn't when the path contains sqlite wildcards
+ "_data LIKE ? AND lower(substr(_data,1,?))=lower(?)",
+ new String[] { hiddenroot + "/%",
+ "" + (hiddenroot.length() + 1), hiddenroot + "/"});
+ helper.mNumUpdates += numrows;
+ ContentResolver res = getContext().getContentResolver();
+ res.notifyChange(Uri.parse("content://media/"), null);
+ }
+
/*
* Rescan files for missing metadata and set their type accordingly.
* There is code for detecting the removal of a nomedia file or renaming of
@@ -3419,8 +3447,12 @@
@Override
public void onMediaScannerConnected() {
- Cursor c = mDb.query("files", openFileColumns, "_data like ?",
- new String[] { mPath + "/%"}, null, null, null);
+ Cursor c = mDb.query("files", openFileColumns,
+ // the "like" test makes use of the index, while the lower() ensures it
+ // doesn't match entries it shouldn't when the path contains sqlite wildcards
+ "_data like ? AND lower(substr(_data,1,?))=lower(?)",
+ new String[] { mPath + "/%", "" + (mPath.length() + 1), mPath + "/"},
+ null, null, null);
while (c.moveToNext()) {
String d = c.getString(0);
File f = new File(d);
@@ -3900,9 +3932,15 @@
sGetTableAndWhereParam.where, whereArgs);
if (count > 0) {
// then update the paths of any files and folders contained in the directory.
- Object[] bindArgs = new Object[] {oldPath + "/%", oldPath.length() + 1, newPath};
+ Object[] bindArgs = new Object[] {newPath, oldPath.length() + 1,
+ oldPath + "/%", (oldPath.length() + 1), oldPath + "/"};
helper.mNumUpdates++;
- db.execSQL("UPDATE files SET _data=?3||SUBSTR(_data, ?2) WHERE _data LIKE ?1;", bindArgs);
+ db.execSQL("UPDATE files SET _data=?1||SUBSTR(_data, ?2)" +
+ // the "like" test makes use of the index, while the lower()
+ // test ensures it doesn't match entries it shouldn't when the
+ // path contains sqlite wildcards
+ " WHERE _data LIKE ?3 AND lower(substr(_data,1,?4))=lower(?5);",
+ bindArgs);
}
if (count > 0 && !db.inTransaction()) {
@@ -4254,6 +4292,10 @@
private File queryForDataFile(Uri uri) throws FileNotFoundException {
final Cursor cursor = query(
uri, new String[] { MediaColumns.DATA }, null, null, null);
+ if (cursor == null) {
+ throw new FileNotFoundException("Missing cursor for " + uri);
+ }
+
try {
switch (cursor.getCount()) {
case 0:
@@ -4281,7 +4323,7 @@
final int modeBits = ContentResolver.modeToMode(uri, mode);
final boolean isWrite = (modeBits & MODE_WRITE_ONLY) != 0;
- final File file = queryForDataFile(uri);
+ File file = queryForDataFile(uri);
final String path;
try {
path = file.getCanonicalPath();
@@ -4297,6 +4339,17 @@
getContext().enforceCallingOrSelfPermission(
WRITE_EXTERNAL_STORAGE, "External path: " + path);
}
+
+ // bypass emulation layer when file is opened for reading, but only
+ // when opening read-only and we have an exact match.
+ if (modeBits == MODE_READ_ONLY && Environment.isExternalStorageEmulated()) {
+ final File directFile = new File(Environment.getMediaStorageDirectory(), path
+ .substring(sExternalPath.length()));
+ if (directFile.exists()) {
+ file = directFile;
+ }
+ }
+
} else if (path.startsWith(sCachePath)) {
getContext().enforceCallingOrSelfPermission(
ACCESS_CACHE_FILESYSTEM, "Cache path: " + path);