Implement compatibility support for WRITE_SDCARD permission.

Now old applications will automatically be granted it.  Also renamed it from
SDCARD_WRITE to WRITE_SDCARD to be consistent with our other permissions,
and re-arranged how we do targetSdkVersion to actually be usuable for this
kind of stuff.

Note that right now this results in basically all apps being given the
WRITE_SDCARD permission, because their targetSdkVersion is not set.  I will
be dealing with that in a future change.
diff --git a/api/current.xml b/api/current.xml
index 1ad643f..8c56f69 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -870,17 +870,6 @@
  visibility="public"
 >
 </field>
-<field name="SDCARD_WRITE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.permission.SDCARD_WRITE&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="SEND_SMS"
  type="java.lang.String"
  transient="false"
@@ -1167,6 +1156,17 @@
  visibility="public"
 >
 </field>
+<field name="WRITE_SDCARD"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.WRITE_SDCARD&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="WRITE_SECURE_SETTINGS"
  type="java.lang.String"
  transient="false"
@@ -34938,6 +34938,16 @@
  visibility="public"
 >
 </field>
+<field name="targetSdkVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="taskAffinity"
  type="java.lang.String"
  transient="false"
@@ -35113,22 +35123,11 @@
  visibility="public"
 >
 </field>
-<field name="FLAG_TARGETS_SDK"
- type="int"
- transient="false"
- volatile="false"
- value="256"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="FLAG_TEST_ONLY"
  type="int"
  transient="false"
  volatile="false"
- value="512"
+ value="256"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -89129,6 +89128,28 @@
  visibility="public"
 >
 </field>
+<field name="CUR_DEVELOPMENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DONUT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Bundle"
  extends="java.lang.Object"
@@ -142794,6 +142815,17 @@
 <implements name="java.lang.annotation.Annotation">
 </implements>
 </class>
+<class name="ViewDebug.FlagToString"
+ extends="java.lang.Object"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.lang.annotation.Annotation">
+</implements>
+</class>
 <class name="ViewDebug.HierarchyTraceType"
  extends="java.lang.Enum"
  abstract="false"
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 88ac04c..ad022e7 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -123,13 +123,7 @@
      * Value for {@link #flags}: this is set of the application has set
      * its android:targetSdkVersion to something >= the current SDK version.
      */
-    public static final int FLAG_TARGETS_SDK = 1<<8;
-
-    /**
-     * Value for {@link #flags}: this is set of the application has set
-     * its android:targetSdkVersion to something >= the current SDK version.
-     */
-    public static final int FLAG_TEST_ONLY = 1<<9;
+    public static final int FLAG_TEST_ONLY = 1<<8;
 
     /**
      * Flags associated with the application.  Any combination of
@@ -137,7 +131,7 @@
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
      * {@link #FLAG_ALLOW_TASK_REPARENTING}
      * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
-     * {@link #FLAG_TARGETS_SDK}.
+     * {@link #FLAG_TEST_ONLY}.
      */
     public int flags = 0;
     
@@ -182,6 +176,16 @@
     public int[] supportsDensities;
 
     /**
+     * The minimum SDK version this application targets.  It may run on earilier
+     * versions, but it knows how to work with any new behavior added at this
+     * version.  Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
+     * if this is a development build and the app is targeting that.  You should
+     * compare that this number is >= the SDK version number at which your
+     * behavior was introduced.
+     */
+    public int targetSdkVersion;
+    
+    /**
      * When false, indicates that all components within this application are
      * considered disabled, regardless of their individually set enabled status.
      */
@@ -200,6 +204,7 @@
         pw.println(prefix + "publicSourceDir=" + publicSourceDir);
         pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
         pw.println(prefix + "dataDir=" + dataDir);
+        pw.println(prefix + "targetSdkVersion=" + targetSdkVersion);
         pw.println(prefix + "enabled=" + enabled);
         pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
         pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
@@ -246,6 +251,7 @@
         sharedLibraryFiles = orig.sharedLibraryFiles;
         dataDir = orig.dataDir;
         uid = orig.uid;
+        targetSdkVersion = orig.targetSdkVersion;
         enabled = orig.enabled;
         manageSpaceActivityName = orig.manageSpaceActivityName;
         descriptionRes = orig.descriptionRes;
@@ -276,6 +282,7 @@
         dest.writeStringArray(sharedLibraryFiles);
         dest.writeString(dataDir);
         dest.writeInt(uid);
+        dest.writeInt(targetSdkVersion);
         dest.writeInt(enabled ? 1 : 0);
         dest.writeString(manageSpaceActivityName);
         dest.writeInt(descriptionRes);
@@ -305,6 +312,7 @@
         sharedLibraryFiles = source.readStringArray();
         dataDir = source.readString();
         uid = source.readInt();
+        targetSdkVersion = source.readInt();
         enabled = source.readInt() != 0;
         manageSpaceActivityName = source.readString();
         descriptionRes = source.readInt();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 88907c1..78462f1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -55,6 +55,30 @@
  * {@hide}
  */
 public class PackageParser {
+    /** @hide */
+    public static class NewPermissionInfo {
+        public final String name;
+        public final int sdkVersion;
+        public final int fileVersion;
+        
+        public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
+            this.name = name;
+            this.sdkVersion = sdkVersion;
+            this.fileVersion = fileVersion;
+        }
+    }
+    
+    /**
+     * 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.
+     * @hide
+     */
+    public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = new PackageParser.NewPermissionInfo[] {
+        new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_SDCARD,
+                android.os.Build.VERSION_CODES.DONUT,
+                0)
+    };
 
     private String mArchiveSourcePath;
     private String[] mSeparateProcesses;
@@ -616,7 +640,6 @@
 
         final Package pkg = new Package(pkgName);
         boolean foundApp = false;
-        boolean targetsSdk = false;
         
         TypedArray sa = res.obtainAttributes(attrs,
                 com.android.internal.R.styleable.AndroidManifest);
@@ -774,11 +797,10 @@
                             return null;
                         }
                         // If the code matches, it definitely targets this SDK.
-                        targetsSdk = true;
-                    } else if (targetVers >= mSdkVersion) {
-                        // If they have explicitly targeted our current version
-                        // or something after it, then note this.
-                        targetsSdk = true;
+                        pkg.applicationInfo.targetSdkVersion
+                                = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
+                    } else {
+                        pkg.applicationInfo.targetSdkVersion = targetVers;
                     }
                     
                     if (minVers > mSdkVersion) {
@@ -824,8 +846,18 @@
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
         }
 
-        if (targetsSdk) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_TARGETS_SDK;
+        final int NP = PackageParser.NEW_PERMISSIONS.length;
+        for (int ip=0; ip<NP; ip++) {
+            final PackageParser.NewPermissionInfo npi
+                    = PackageParser.NEW_PERMISSIONS[ip];
+            if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
+                break;
+            }
+            if (!pkg.requestedPermissions.contains(npi.name)) {
+                Log.i(TAG, "Impliciting adding " + npi.name + " to old pkg "
+                        + pkg.packageName);
+                pkg.requestedPermissions.add(npi.name);
+            }
         }
         
         if (pkg.usesLibraries.size() > 0) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 5487c54..4a4285e 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -87,6 +87,12 @@
      */
     public static class VERSION_CODES {
         /**
+         * Magic version number for a current development build, which has
+         * not yet turned into an official release.
+         */
+        public static final int CUR_DEVELOPMENT = 10000;
+        
+        /**
          * October 2008: The original, first, version of Android.  Yay!
          */
         public static final int BASE = 1;
@@ -98,6 +104,19 @@
          * May 2009: Android 1.5.
          */
         public static final int CUPCAKE = 3;
+        /**
+         * Current work on "Donut" development branch.
+         * 
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li> They must explicitly request the
+         * {@link android.Manifest.permission#WRITE_SDCARD} permission to be
+         * able to modify the contents of the SD card.  (Apps targeting
+         * earlier versions will always request the permission.)
+         * </ul>
+         */
+        public static final int DONUT = CUR_DEVELOPMENT;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 05fbe64..d4b314a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -389,11 +389,11 @@
         android:description="@string/permgroupdesc_storage" />
 
     <!-- Allows an application to write to the SD card -->
-    <permission android:name="android.permission.SDCARD_WRITE"
+    <permission android:name="android.permission.WRITE_SDCARD"
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardWrite"
         android:description="@string/permdesc_sdcardWrite"
-        android:protectionLevel="normal" />
+        android:protectionLevel="dangerous" />
 
     <!-- ============================================ -->
     <!-- Permissions for low-level system interaction -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9ddfa82..ce716b1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1076,7 +1076,7 @@
       user dictionary.</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">write to SD card</string>
+    <string name="permlab_sdcardWrite">modify/delete 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. -->
     <string name="permdesc_sdcardWrite">Allows an application to write to the SD card.</string>
 
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index f80bd6b..526b6d9 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -54,7 +54,7 @@
         <group gid="log" />
     </permission>
 
-    <permission name="android.permission.SDCARD_WRITE" >
+    <permission name="android.permission.WRITE_SDCARD" >
         <group gid="sdcard_rw" />
     </permission>
 
@@ -84,6 +84,24 @@
          others should have a fairly open environment in which to
          interact with the system. -->
 
+    <!-- Standard permissions granted to the shell. -->
+    <assign-permission name="android.permission.WRITE_SDCARD" uid="shell" />
+    <assign-permission name="android.permission.SEND_SMS" uid="shell" />
+    <assign-permission name="android.permission.CALL_PHONE" uid="shell" />
+    <assign-permission name="android.permission.READ_CONTACTS" uid="shell" />
+    <assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" />
+    <assign-permission name="android.permission.READ_OWNER_DATA" uid="shell" />
+    <assign-permission name="android.permission.WRITE_OWNER_DATA" uid="shell" />
+    <assign-permission name="android.permission.READ_CALENDAR" uid="shell" />
+    <assign-permission name="android.permission.WRITE_CALENDAR" uid="shell" />
+    <assign-permission name="android.permission.READ_USER_DICTIONARY" uid="shell" />
+    <assign-permission name="android.permission.WRITE_USER_DICTIONARY" uid="shell" />
+    <assign-permission name="android.permission.ACCESS_FINE_LOCATION" uid="shell" />
+    <assign-permission name="android.permission.ACCESS_COARSE_LOCATION" uid="shell" />
+    <assign-permission name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" uid="shell" />
+    <assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" />
+    <assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" />
+    <assign-permission name="android.permission.BLUETOOTH" uid="shell" />
     <!-- System tool permissions granted to the shell. -->
     <assign-permission name="android.permission.GET_TASKS" uid="shell" />
     <assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" />
@@ -114,6 +132,8 @@
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="shell" />
     <assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" />
     <assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
+    <assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
+    <assign-permission name="android.permission.INSTALL_LOCATION_COLLECTOR" uid="shell" />
 
     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
     <assign-permission name="android.permission.ACCESS_DRM" uid="media" />
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 5194aea..0007066 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2831,6 +2831,21 @@
                         // we can't add any new permissions to it.
                         if (!gp.loadedPermissions.contains(perm)) {
                             allowed = false;
+                            // Except...  if this is a permission that was added
+                            // to the platform (note: need to only do this when
+                            // updating the platform).
+                            final int NP = PackageParser.NEW_PERMISSIONS.length;
+                            for (int ip=0; ip<NP; ip++) {
+                                final PackageParser.NewPermissionInfo npi
+                                        = PackageParser.NEW_PERMISSIONS[ip];
+                                if (npi.name.equals(perm)
+                                        && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
+                                    allowed = true;
+                                    Log.i(TAG, "Auto-granting WRITE_SDCARD to old pkg "
+                                            + pkg.packageName);
+                                    break;
+                                }
+                            }
                         }
                     }
                     if (allowed) {
@@ -3589,7 +3604,9 @@
         } else {
             // Re installation failed. Restore old information
             // Remove new pkg information
-            removePackageLI(newPackage, true);
+            if (newPackage != null) {
+                removePackageLI(newPackage, true);
+            }
             // Add back the old system package
             scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath, 
                     oldPkgSetting.resourcePath,
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 2d8471b..216ece4 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -99,6 +99,17 @@
     const android::Vector<const char*>& getNoCompressExtensions() const { return mNoCompressExtensions; }
     void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); }
 
+    const char*  getMinSdkVersion() const { return mMinSdkVersion; }
+    void setMinSdkVersion(const char*  val) { mMinSdkVersion = val; }
+    const char*  getTargetSdkVersion() const { return mTargetSdkVersion; }
+    void setTargetSdkVersion(const char*  val) { mTargetSdkVersion = val; }
+    const char*  getMaxSdkVersion() const { return mMaxSdkVersion; }
+    void setMaxSdkVersion(const char*  val) { mMaxSdkVersion = val; }
+    const char*  getVersionCode() const { return mVersionCode; }
+    void setVersionCode(const char*  val) { mVersionCode = val; }
+    const char* getVersionName() const { return mVersionName; }
+    void setVersionName(const char* val) { mVersionName = val; }
+    
     /*
      * Set and get the file specification.
      *
@@ -151,6 +162,12 @@
     android::Vector<const char*> mNoCompressExtensions;
     android::Vector<const char*> mResourceSourceDirs;
     
+    const char* mMinSdkVersion;
+    const char* mTargetSdkVersion;
+    const char* mMaxSdkVersion;
+    const char* mVersionCode;
+    const char* mVersionName;
+    
     /* file specification */
     int         mArgc;
     char* const* mArgv;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 71b1a3c..8bf2b07 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -54,9 +54,10 @@
         "   xmlstrings       Print the strings of the given compiled xml assets.\n\n", gProgName);
     fprintf(stderr,
         " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
-        "        [-0 extension [-0 extension ...]] \\\n"
-        "        [-g tolerance] \\\n"
-        "        [-j jarfile] \\\n"
+        "        [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
+        "        [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
+        "        [--max-sdk-version VAL] [--app-version VAL] \\\n"
+        "        [--app-version-name TEXT] \\\n"
         "        [-I base-package [-I base-package ...]] \\\n"
         "        [-A asset-source-dir] [-P public-definitions-file] \\\n"
         "        [-S resource-sources [-S resource-sources ...]] "
@@ -115,7 +116,17 @@
         "       and the first match found (left to right) will take precedence."
         "   -0  specifies an additional extension for which such files will not\n"
         "       be stored compressed in the .apk.  An empty string means to not\n"
-        "       compress any files at all.\n");
+        "       compress any files at all.\n"
+        "   --min-sdk-version\n"
+        "       inserts android:minSdkVersion in to manifest.\n"
+        "   --target-sdk-version\n"
+        "       inserts android:targetSdkVersion in to manifest.\n"
+        "   --max-sdk-version\n"
+        "       inserts android:maxSdkVersion in to manifest.\n"
+        "   --version-code\n"
+        "       inserts android:versionCode in to manifest.\n"
+        "   --version-name\n"
+        "       inserts android:versionName in to manifest.\n");
 }
 
 /*
@@ -339,6 +350,59 @@
                     bundle.setCompressionMethod(ZipEntry::kCompressStored);
                 }
                 break;
+            case '-':
+                if (strcmp(cp, "-min-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setMinSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-target-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setTargetSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-max-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setMaxSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-version-code") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setVersionCode(argv[0]);
+                } else if (strcmp(cp, "-version-name") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setVersionName(argv[0]);
+                } else {
+                    fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
+                    wantUsage = true;
+                    goto bail;
+                }
+                cp += strlen(cp) - 1;
+                break;
             default:
                 fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp);
                 wantUsage = true;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 2e4d0a4..76b9d0a 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -488,6 +488,58 @@
     return;
 }
 
+void addTagAttribute(const sp<XMLNode>& node, const char* ns8,
+        const char* attr8, const char* value)
+{
+    if (value == NULL) {
+        return;
+    }
+    
+    const String16 ns(ns8);
+    const String16 attr(attr8);
+    
+    if (node->getAttribute(ns, attr) != NULL) {
+        fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n",
+                String8(attr).string(), String8(ns).string());
+        return;
+    }
+    
+    node->addAttribute(ns, attr, String16(value));
+}
+
+status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
+{
+    root = root->searchElement(String16(), String16("manifest"));
+    if (root == NULL) {
+        fprintf(stderr, "No <manifest> tag.\n");
+        return UNKNOWN_ERROR;
+    }
+    
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
+            bundle->getVersionCode());
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
+            bundle->getVersionName());
+    
+    if (bundle->getMinSdkVersion() != NULL
+            || bundle->getTargetSdkVersion() != NULL
+            || bundle->getMaxSdkVersion() != NULL) {
+        sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
+        if (vers == NULL) {
+            vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
+            root->insertChildAt(vers, 0);
+        }
+        
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion",
+                bundle->getMinSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion",
+                bundle->getTargetSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion",
+                bundle->getMaxSdkVersion());
+    }
+    
+    return NO_ERROR;
+}
+
 #define ASSIGN_IT(n) \
         do { \
             ssize_t index = resources->indexOfKey(String8(#n)); \
@@ -1006,7 +1058,15 @@
 
     // Generate final compiled manifest file.
     manifestFile->clearData();
-    err = compileXmlFile(assets, manifestFile, &table);
+    sp<XMLNode> manifestTree = XMLNode::parse(manifestFile);
+    if (manifestTree == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    err = massageManifest(bundle, manifestTree);
+    if (err < NO_ERROR) {
+        return err;
+    }
+    err = compileXmlFile(assets, manifestTree, manifestFile, &table);
     if (err < NO_ERROR) {
         return err;
     }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index ef11a83..25ab147 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -23,6 +23,16 @@
     if (root == NULL) {
         return UNKNOWN_ERROR;
     }
+    
+    return compileXmlFile(assets, root, target, table, options);
+}
+
+status_t compileXmlFile(const sp<AaptAssets>& assets,
+                        const sp<XMLNode>& root,
+                        const sp<AaptFile>& target,
+                        ResourceTable* table,
+                        int options)
+{
     if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
         root->removeWhitespace(true, NULL);
     } else  if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
@@ -1307,7 +1317,7 @@
             } else if (id != 0) {
                 if (id == 127) {
                     if (mHaveAppPackage) {
-                        fprintf(stderr, "Included resource have two application packages!\n");
+                        fprintf(stderr, "Included resources have two application packages!\n");
                         return UNKNOWN_ERROR;
                     }
                     mHaveAppPackage = true;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 74ba326..665232b 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -15,6 +15,7 @@
 
 using namespace std;
 
+class XMLNode;
 class ResourceTable;
 
 enum {
@@ -34,6 +35,12 @@
                         ResourceTable* table,
                         int options = XML_COMPILE_STANDARD_RESOURCE);
 
+status_t compileXmlFile(const sp<AaptAssets>& assets,
+                        const sp<XMLNode>& xmlTree,
+                        const sp<AaptFile>& target,
+                        ResourceTable* table,
+                        int options = XML_COMPILE_STANDARD_RESOURCE);
+
 status_t compileResourceFile(Bundle* bundle,
                              const sp<AaptAssets>& assets,
                              const sp<AaptFile>& in,
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 50a2185..832ba6c 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -525,12 +525,30 @@
     return mChildren;
 }
 
+const String8& XMLNode::getFilename() const
+{
+    return mFilename;
+}
+    
 const Vector<XMLNode::attribute_entry>&
     XMLNode::getAttributes() const
 {
     return mAttributes;
 }
 
+const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns,
+        const String16& name) const
+{
+    for (size_t i=0; i<mAttributes.size(); i++) {
+        const attribute_entry& ae(mAttributes.itemAt(i));
+        if (ae.ns == ns && ae.name == name) {
+            return &ae;
+        }
+    }
+    
+    return NULL;
+}
+
 const String16& XMLNode::getCData() const
 {
     return mChars;
@@ -551,6 +569,38 @@
     return mEndLineNumber;
 }
 
+sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& tagName)
+{
+    if (getType() == XMLNode::TYPE_ELEMENT
+            && mNamespaceUri == tagNamespace
+            && mElementName == tagName) {
+        return this;
+    }
+    
+    for (size_t i=0; i<mChildren.size(); i++) {
+        sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName);
+        if (found != NULL) {
+            return found;
+        }
+    }
+    
+    return NULL;
+}
+
+sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName)
+{
+    for (size_t i=0; i<mChildren.size(); i++) {
+        sp<XMLNode> child = mChildren.itemAt(i);
+        if (child->getType() == XMLNode::TYPE_ELEMENT
+                && child->mNamespaceUri == tagNamespace
+                && child->mElementName == tagName) {
+            return child;
+        }
+    }
+    
+    return NULL;
+}
+
 status_t XMLNode::addChild(const sp<XMLNode>& child)
 {
     if (getType() == TYPE_CDATA) {
@@ -562,6 +612,17 @@
     return NO_ERROR;
 }
 
+status_t XMLNode::insertChildAt(const sp<XMLNode>& child, size_t index)
+{
+    if (getType() == TYPE_CDATA) {
+        SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node.");
+        return UNKNOWN_ERROR;
+    }
+    //printf("Adding child %p to parent %p\n", child.get(), this);
+    mChildren.insertAt(child, index);
+    return NO_ERROR;
+}
+
 status_t XMLNode::addAttribute(const String16& ns, const String16& name,
                                const String16& value)
 {
diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h
index 86548a2..a9bea43 100644
--- a/tools/aapt/XMLNode.h
+++ b/tools/aapt/XMLNode.h
@@ -68,6 +68,8 @@
     const String16& getElementName() const;
     const Vector<sp<XMLNode> >& getChildren() const;
 
+    const String8& getFilename() const;
+    
     struct attribute_entry {
         attribute_entry() : index(~(uint32_t)0), nameResId(0)
         {
@@ -91,6 +93,8 @@
 
     const Vector<attribute_entry>& getAttributes() const;
 
+    const attribute_entry* getAttribute(const String16& ns, const String16& name) const;
+    
     const String16& getCData() const;
 
     const String16& getComment() const;
@@ -98,8 +102,14 @@
     int32_t getStartLineNumber() const;
     int32_t getEndLineNumber() const;
 
+    sp<XMLNode> searchElement(const String16& tagNamespace, const String16& tagName);
+    
+    sp<XMLNode> getChildElement(const String16& tagNamespace, const String16& tagName);
+    
     status_t addChild(const sp<XMLNode>& child);
 
+    status_t insertChildAt(const sp<XMLNode>& child, size_t index);
+
     status_t addAttribute(const String16& ns, const String16& name,
                           const String16& value);