Merge tag 'android-4.4.1_r1' into kitkat

Android 4.4.1 Release 1
diff --git a/src/com/android/providers/media/MediaDocumentsProvider.java b/src/com/android/providers/media/MediaDocumentsProvider.java
index cb8cc2f..a887a83 100644
--- a/src/com/android/providers/media/MediaDocumentsProvider.java
+++ b/src/com/android/providers/media/MediaDocumentsProvider.java
@@ -476,7 +476,7 @@
         try {
             cursor = resolver.query(uri, new String[] {
                     BaseColumns._ID }, null, null, null);
-            return (cursor.getCount() == 0);
+            return (cursor == null) || (cursor.getCount() == 0);
         } finally {
             IoUtils.closeQuietly(cursor);
             Binder.restoreCallingIdentity(token);
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 3e03ae6..4528c56 100755
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -60,7 +60,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
@@ -127,16 +126,21 @@
     private static final String sExternalPath;
     /** Resolved canonical path to cache storage. */
     private static final String sCachePath;
+    /** Resolved canonical path to legacy storage. */
+    private static final String sLegacyPath;
 
     static {
         try {
             sExternalPath = Environment.getExternalStorageDirectory().getCanonicalPath();
             sCachePath = Environment.getDownloadCacheDirectory().getCanonicalPath();
+            sLegacyPath = Environment.getLegacyExternalStorageDirectory().getCanonicalPath();
         } catch (IOException e) {
             throw new RuntimeException("Unable to resolve canonical paths", e);
         }
     }
 
+    private StorageManager mStorageManager;
+
     // In memory cache of path<->id mappings, to speed up inserts during media scan
     HashMap<String, Long> mDirectoryCache = new HashMap<String, Long>();
 
@@ -546,6 +550,8 @@
     public boolean onCreate() {
         final Context context = getContext();
 
+        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+
         sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " +
                 MediaStore.Audio.Albums._ID);
         sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album");
@@ -4165,8 +4171,11 @@
                                 sGetTableAndWhereParam.where, whereArgs);
                         if (count > 0) {
                             // update the paths of any files and folders contained in the directory
-                            Object[] bindArgs = new Object[] {newPath, oldPath.length() + 1,
-                                    oldPath + "/", oldPath + "0",
+                            Object[] bindArgs = new Object[] {
+                                    newPath,
+                                    oldPath.length() + 1,
+                                    oldPath + "/",
+                                    oldPath + "0",
                                     // update bucket_display_name and bucket_id based on new path
                                     f.getName(),
                                     f.toString().toLowerCase().hashCode()
@@ -4174,8 +4183,8 @@
                             helper.mNumUpdates++;
                             db.execSQL("UPDATE files SET _data=?1||SUBSTR(_data, ?2)" +
                                     // also update bucket_display_name
-                                    ",bucket_display_name=?6" +
-                                    ",bucket_id=?7" +
+                                    ",bucket_display_name=?5" +
+                                    ",bucket_id=?6" +
                                     " WHERE _data >= ?3 AND _data < ?4;",
                                     bindArgs);
                         }
@@ -4596,10 +4605,13 @@
             throw new IllegalArgumentException("Unable to resolve canonical path for " + file, e);
         }
 
-        if (path.startsWith(sExternalPath)) {
-            Context c = getContext();
-            if (c.checkCallingOrSelfUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
-                    != PackageManager.PERMISSION_GRANTED) {
+        Context c = getContext();
+        boolean readGranted =
+                (c.checkCallingOrSelfUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                == PackageManager.PERMISSION_GRANTED);
+
+        if (path.startsWith(sExternalPath) || path.startsWith(sLegacyPath)) {
+            if (!readGranted) {
                 c.enforceCallingOrSelfPermission(
                         READ_EXTERNAL_STORAGE, "External path: " + path);
             }
@@ -4613,15 +4625,19 @@
             }
 
         } else if (path.startsWith(sCachePath)) {
-            getContext().enforceCallingOrSelfPermission(
-                    ACCESS_CACHE_FILESYSTEM, "Cache path: " + path);
+            if (!readGranted) {
+                c.enforceCallingOrSelfPermission(
+                        ACCESS_CACHE_FILESYSTEM, "Cache path: " + path);
+            }
         } else if (isWrite) {
             // don't write to non-cache, non-sdcard files.
             throw new FileNotFoundException("Can't access " + file);
         } else if (isSecondaryExternalPath(path)) {
             // read access is OK with the appropriate permission
-            getContext().enforceCallingOrSelfPermission(
-                    READ_EXTERNAL_STORAGE, "External path: " + path);
+            if (!readGranted) {
+                c.enforceCallingOrSelfPermission(
+                        READ_EXTERNAL_STORAGE, "External path: " + path);
+            }
         } else {
             checkWorldReadAccess(path);
         }
@@ -5225,16 +5241,15 @@
                         false, mObjectRemovedCallback);
             } else if (EXTERNAL_VOLUME.equals(volume)) {
                 if (Environment.isExternalStorageRemovable()) {
-                    String path = mExternalStoragePaths[0];
-                    int volumeID = FileUtils.getFatVolumeId(path);
-                    if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID);
+                    final StorageVolume actualVolume = mStorageManager.getPrimaryVolume();
+                    final int volumeId = actualVolume.getFatVolumeId();
 
                     // Must check for failure!
                     // If the volume is not (yet) mounted, this will create a new
                     // external-ffffffff.db database instead of the one we expect.  Then, if
                     // android.process.media is later killed and respawned, the real external
                     // database will be attached, containing stale records, or worse, be empty.
-                    if (volumeID == -1) {
+                    if (volumeId == -1) {
                         String state = Environment.getExternalStorageState();
                         if (Environment.MEDIA_MOUNTED.equals(state) ||
                                 Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
@@ -5253,10 +5268,10 @@
                     }
 
                     // generate database name based on volume ID
-                    String dbName = "external-" + Integer.toHexString(volumeID) + ".db";
+                    String dbName = "external-" + Integer.toHexString(volumeId) + ".db";
                     helper = new DatabaseHelper(context, dbName, false,
                             false, mObjectRemovedCallback);
-                    mVolumeId = volumeID;
+                    mVolumeId = volumeId;
                 } else {
                     // external database name should be EXTERNAL_DATABASE_NAME
                     // however earlier releases used the external-XXXXXXXX.db naming