Add new READ_EXTERNAL_STORAGE permission.

Also adds some initial compatibility code for dealing with it.

Change-Id: I104bff11798349e4aaa6da9b7be787b257daa1bb
diff --git a/api/current.txt b/api/current.txt
index f7d6bce..e677eb2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -76,6 +76,7 @@
     field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
     field public static final java.lang.String READ_CALENDAR = "android.permission.READ_CALENDAR";
     field public static final java.lang.String READ_CONTACTS = "android.permission.READ_CONTACTS";
+    field public static final java.lang.String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
     field public static final java.lang.String READ_FRAME_BUFFER = "android.permission.READ_FRAME_BUFFER";
     field public static final java.lang.String READ_HISTORY_BOOKMARKS = "com.android.browser.permission.READ_HISTORY_BOOKMARKS";
     field public static final java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e88ee02..207f077 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -89,11 +89,25 @@
             this.fileVersion = fileVersion;
         }
     }
-    
+
+    /** @hide */
+    public static class SplitPermissionInfo {
+        public final String rootPerm;
+        public final String[] newPerms;
+
+        public SplitPermissionInfo(String rootPerm, String[] newPerms) {
+            this.rootPerm = rootPerm;
+            this.newPerms = newPerms;
+        }
+    }
+
     /**
      * List of new permissions that have been added since 1.0.
      * NOTE: These must be declared in SDK version order, with permissions
      * added to older SDKs appearing before those added to newer SDKs.
+     * If sdkVersion is 0, then this is not a permission that we want to
+     * automatically add to older apps, but we do want to allow it to be
+     * granted during a platform update.
      * @hide
      */
     public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
@@ -104,6 +118,17 @@
                     android.os.Build.VERSION_CODES.DONUT, 0)
     };
 
+    /**
+     * List of permissions that have been split into more granular or dependent
+     * permissions.
+     * @hide
+     */
+    public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
+        new PackageParser.SplitPermissionInfo[] {
+            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                    new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE })
+    };
+
     private String mArchiveSourcePath;
     private String[] mSeparateProcesses;
     private boolean mOnlyCoreApps;
@@ -1245,7 +1270,23 @@
         if (implicitPerms != null) {
             Slog.i(TAG, implicitPerms.toString());
         }
-        
+
+        final int NS = PackageParser.SPLIT_PERMISSIONS.length;
+        for (int is=0; is<NS; is++) {
+            final PackageParser.SplitPermissionInfo spi
+                    = PackageParser.SPLIT_PERMISSIONS[is];
+            if (!pkg.requestedPermissions.contains(spi.rootPerm)) {
+                break;
+            }
+            for (int in=0; in<spi.newPerms.length; in++) {
+                final String perm = spi.newPerms[in];
+                if (!pkg.requestedPermissions.contains(perm)) {
+                    pkg.requestedPermissions.add(perm);
+                    pkg.requestedPermissionsRequired.add(Boolean.TRUE);
+                }
+            }
+        }
+
         if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
                 && pkg.applicationInfo.targetSdkVersion
                         >= android.os.Build.VERSION_CODES.DONUT)) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 17d2212..8f03fe0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -639,6 +639,13 @@
         android:label="@string/permgrouplab_storage"
         android:description="@string/permgroupdesc_storage" />
 
+    <!-- Allows an application to read from external storage -->
+    <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
+        android:permissionGroup="android.permission-group.STORAGE"
+        android:label="@string/permlab_sdcardRead"
+        android:description="@string/permdesc_sdcardRead"
+        android:protectionLevel="dangerous" />
+
     <!-- Allows an application to write to external storage -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.STORAGE"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c8df649..7137b7c 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1429,6 +1429,15 @@
       user dictionary.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+    <string name="permlab_sdcardRead" product="nosdcard">read USB storage contents</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_sdcardRead" product="default">read SD card contents</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+    <string name="permdesc_sdcardRead" product="nosdcard">Allows the app to read contents of USB storage.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_sdcardRead" product="default">Allows the app to read contents of SD card.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
     <string name="permlab_sdcardWrite" product="nosdcard">modify/delete USB storage contents</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_sdcardWrite" product="default">modify/delete SD card contents</string>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 8be1db2..4b93e74 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -54,6 +54,10 @@
         <group gid="log" />
     </permission>
 
+    <permission name="android.permission.READ_EXTERNAL_STORAGE" >
+        <group gid="sdcard_r" />
+    </permission>
+
     <permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
         <group gid="sdcard_rw" />
     </permission>
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index c79e243..198fce4 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -636,6 +636,9 @@
             bool hasWriteExternalStoragePermission = false;
             bool hasReadPhoneStatePermission = false;
 
+            // If an app requests write storage, they will also get read storage.
+            bool hasReadExternalStoragePermission = false;
+
             // This next group of variables is used to implement a group of
             // backward-compatibility heuristics necessitated by the addition of
             // some new uses-feature constants in 2.1 and 2.2. In most cases, the
@@ -999,6 +1002,8 @@
                                 hasTelephonyPermission = true;
                             } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
                                 hasWriteExternalStoragePermission = true;
+                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
+                                hasReadExternalStoragePermission = true;
                             } else if (name == "android.permission.READ_PHONE_STATE") {
                                 hasReadPhoneStatePermission = true;
                             }
@@ -1163,12 +1168,19 @@
             if (targetSdk < 4) {
                 if (!hasWriteExternalStoragePermission) {
                     printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
+                    hasWriteExternalStoragePermission = true;
                 }
                 if (!hasReadPhoneStatePermission) {
                     printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
                 }
             }
 
+            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
+            // force them to always take READ_EXTERNAL_STORAGE as well.
+            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
+                printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
+            }
+
             /* The following blocks handle printing "inferred" uses-features, based
              * on whether related features or permissions are used by the app.
              * Note that the various spec*Feature variables denote whether the