Implement targetSdkVersion and maxSdkVersion, plus version code names.

This adds new attributes for specifying a targetSdkVersion and maxSdkVersion.
There is a new ApplicationInfo flag that is set if the application has set
its targetSdkVersion to the current platform or later.  Also you can now
use a string for minSdkVersion and targetSdkVerion, to indicate you are
building against a development tree instead of an official platform.
diff --git a/api/current.xml b/api/current.xml
index f809c09..656b12b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -5113,6 +5113,17 @@
  visibility="public"
 >
 </field>
+<field name="maxSdkVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843377"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="maxWidth"
  type="int"
  transient="false"
@@ -7192,6 +7203,17 @@
  visibility="public"
 >
 </field>
+<field name="targetSdkVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843376"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="taskAffinity"
  type="int"
  transient="false"
@@ -31852,6 +31874,28 @@
  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_UPDATED_SYSTEM_APP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="className"
  type="java.lang.String"
  transient="false"
@@ -34085,6 +34129,17 @@
  visibility="public"
 >
 </field>
+<field name="INSTALL_FAILED_NEWER_SDK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-14"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="INSTALL_FAILED_NO_SHARED_USER"
  type="int"
  transient="false"
@@ -85947,6 +86002,66 @@
  volatile="false"
  static="true"
  final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="SDK_INT"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Build.VERSION_CODES"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Build.VERSION_CODES"
+ type="android.os.Build.VERSION_CODES"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="BASE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BASE_1_1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CUPCAKE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
  deprecated="not deprecated"
  visibility="public"
 >
@@ -86088,6 +86203,16 @@
  visibility="public"
 >
 </constructor>
+<field name="CODENAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="INCREMENTAL"
  type="java.lang.String"
  transient="false"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 161bb46..04e69e3 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -537,6 +537,9 @@
         case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER:
             s = "INSTALL_FAILED_CONFLICTING_PROVIDER";
             break;
+        case PackageManager.INSTALL_FAILED_NEWER_SDK:
+            s = "INSTALL_FAILED_NEWER_SDK";
+            break;
         case PackageManager.INSTALL_PARSE_FAILED_NOT_APK:
             s = "INSTALL_PARSE_FAILED_NOT_APK";
             break;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 173057c..fa9ec6e 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -113,19 +113,25 @@
      */
     public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6;
     
-    
     /**
-     * Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
-     *  {@hide}
+     * Value for {@link #flags}: this is set if this application has been
+     * install as an update to a built-in system application.
      */
     public static final int FLAG_UPDATED_SYSTEM_APP = 1<<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;
 
     /**
      * Flags associated with the application.  Any combination of
      * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
      * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
      * {@link #FLAG_ALLOW_TASK_REPARENTING}
-     * {@link #FLAG_ALLOW_CLEAR_USER_DATA}.
+     * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
+     * {@link #FLAG_TARGETS_SDK}.
      */
     public int flags = 0;
     
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9e06666..d21252b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -355,6 +355,14 @@
     public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
 
     /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the new package failed because the current SDK version is newer than
+     * that required by the package.
+     */
+    public static final int INSTALL_FAILED_NEWER_SDK = -14;
+
+    /**
      * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
      * if the parser was given a path that is not a file, or does not end with the expected
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f9c4984..12df5bd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -59,6 +59,7 @@
     private String mArchiveSourcePath;
     private String[] mSeparateProcesses;
     private int mSdkVersion;
+    private String mSdkCodename;
 
     private int mParseError = PackageManager.INSTALL_SUCCEEDED;
 
@@ -123,8 +124,9 @@
         mSeparateProcesses = procs;
     }
 
-    public void setSdkVersion(int sdkVersion) {
+    public void setSdkVersion(int sdkVersion, String codename) {
         mSdkVersion = sdkVersion;
+        mSdkCodename = codename;
     }
 
     private static final boolean isPackageFilename(String name) {
@@ -613,9 +615,9 @@
         int type;
 
         final Package pkg = new Package(pkgName);
-        pkg.mSystem = (flags&PARSE_IS_SYSTEM) != 0;
         boolean foundApp = false;
-
+        boolean targetsSdk = false;
+        
         TypedArray sa = res.obtainAttributes(attrs,
                 com.android.internal.R.styleable.AndroidManifest);
         pkg.mVersionCode = sa.getInteger(
@@ -721,19 +723,74 @@
 
                 XmlUtils.skipCurrentTag(parser);
 
-            }  else if (tagName.equals("uses-sdk")) {
+            } else if (tagName.equals("uses-sdk")) {
                 if (mSdkVersion > 0) {
                     sa = res.obtainAttributes(attrs,
                             com.android.internal.R.styleable.AndroidManifestUsesSdk);
 
-                    int vers = sa.getInt(
-                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion, 0);
+                    int minVers = 0;
+                    String minCode = null;
+                    int targetVers = 0;
+                    String targetCode = null;
+                    
+                    TypedValue val = sa.peekValue(
+                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+                    if (val != null) {
+                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                            targetCode = minCode = val.string.toString();
+                        } else {
+                            // If it's not a string, it's an integer.
+                            minVers = val.data;
+                        }
+                    }
+                    
+                    val = sa.peekValue(
+                            com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+                    if (val != null) {
+                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                            targetCode = minCode = val.string.toString();
+                        } else {
+                            // If it's not a string, it's an integer.
+                            targetVers = val.data;
+                        }
+                    }
+                    
+                    int maxVers = sa.getInt(
+                            com.android.internal.R.styleable.AndroidManifestUsesSdk_maxSdkVersion,
+                            mSdkVersion);
 
                     sa.recycle();
 
-                    if (vers > mSdkVersion) {
-                        outError[0] = "Requires newer sdk version #" + vers
-                            + " (current version is #" + mSdkVersion + ")";
+                    if (targetCode != null) {
+                        if (!targetCode.equals(mSdkCodename)) {
+                            if (mSdkCodename != null) {
+                                outError[0] = "Requires development platform " + targetCode
+                                        + " (current platform is " + mSdkCodename + ")";
+                            } else {
+                                outError[0] = "Requires development platform " + targetCode
+                                        + " but this is a release platform.";
+                            }
+                            mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                            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;
+                    }
+                    
+                    if (minVers > mSdkVersion) {
+                        outError[0] = "Requires newer sdk version #" + minVers
+                                + " (current version is #" + mSdkVersion + ")";
+                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                        return null;
+                    }
+                    
+                    if (maxVers < mSdkVersion) {
+                        outError[0] = "Requires older sdk version #" + maxVers
+                                + " (current version is #" + mSdkVersion + ")";
                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                         return null;
                     }
@@ -767,6 +824,10 @@
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
         }
 
+        if (targetsSdk) {
+            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_TARGETS_SDK;
+        }
+        
         if (pkg.usesLibraries.size() > 0) {
             pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()];
             pkg.usesLibraries.toArray(pkg.usesLibraryFiles);
@@ -2133,9 +2194,6 @@
         // If this is a 3rd party app, this is the path of the zip file.
         public String mPath;
 
-        // True if this package is part of the system image.
-        public boolean mSystem;
-
         // The version code declared for this package.
         public int mVersionCode;
         
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 467c17f..5487c54 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -59,11 +59,47 @@
         public static final String RELEASE = getString("ro.build.version.release");
 
         /**
-         * The user-visible SDK version of the framework. It is an integer starting at 1.
+         * The user-visible SDK version of the framework in its raw String
+         * representation; use {@link #SDK_INT} instead.
+         * 
+         * @deprecated Use {@link #SDK_INT} to easily get this as an integer.
          */
         public static final String SDK = getString("ro.build.version.sdk");
+
+        /**
+         * The user-visible SDK version of the framework; its possible
+         * values are defined in {@link Build.VERSION_CODES}.
+         */
+        public static final int SDK_INT = SystemProperties.getInt(
+                "ro.build.version.sdk", 0);
+
+        /**
+         * The current development codename, or the string "REL" if this is
+         * a release build.
+         */
+        public static final String CODENAME = getString("ro.build.version.codename");
     }
 
+    /**
+     * Enumeration of the currently known SDK version codes.  These are the
+     * values that can be found in {@link VERSION#SDK}.  Version numbers
+     * increment monotonically with each official platform release.
+     */
+    public static class VERSION_CODES {
+        /**
+         * October 2008: The original, first, version of Android.  Yay!
+         */
+        public static final int BASE = 1;
+        /**
+         * February 2009: First Android update, officially called 1.1.
+         */
+        public static final int BASE_1_1 = 2;
+        /**
+         * May 2009: Android 1.5.
+         */
+        public static final int CUPCAKE = 3;
+    }
+    
     /** The type of build, like "user" or "eng". */
     public static final String TYPE = getString("ro.build.type");
 
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 54da326..1319c77 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -753,9 +753,28 @@
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestUsesSdk" parent="AndroidManifest">
         <!-- This is the minimum SDK version number that the application
-             requires.  Currently there is only one SDK version, 1.  If
-             not supplied, the application will work on any SDK. -->
-        <attr name="minSdkVersion" format="integer" />
+             requires.  This number is an abstract integer, from the list
+             in {@link android.os.Build.VERSION_CODES}  If
+             not supplied, the application will work on any SDK.  This
+             may also be string (such as "Donut") if the application was built
+             against a development branch, in which case it will only work against
+             the development builds. -->
+        <attr name="minSdkVersion" format="integer|string" />
+        <!-- This is the SDK version number that the application is targeting.
+             It is able to run on older versions (down to minSdkVersion), but
+             was explicitly tested to work with the version specified here.
+             Specifying this version allows the platform to disable compatibility
+             code that are not required or enable newer features that are not
+             available to older applications.  This may also be a string
+             (such as "Donut") if this is built against a development
+             branch, in which case minSdkVersion is also forced to be that
+             string. -->
+        <attr name="targetSdkVersion" format="integer|string" />
+        <!-- This is the maximum SDK version number that an application works
+             on.  You can use this to ensure your application is filtered out
+             of later versions of the platform when you know you have
+             incompatibility with them. -->
+        <attr name="maxSdkVersion" format="integer" />
     </declare-styleable>
     
     <!-- The <code>uses-libraries</code> specifies a shared library that this
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9e4c6a9..df5d879 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1087,7 +1087,7 @@
   <public type="integer" name="config_longAnimTime" id="0x010e0002" />
 
 <!-- ===============================================================
-     Resources added in version 4 of the platform.
+     Resources added in Donut.
      =============================================================== -->
   <eat-comment />
 
@@ -1097,6 +1097,8 @@
    <public type="attr" name="searchSuggestThreshold" id="0x0101026d" />
    <public type="attr" name="includeInGlobalSearch" id="0x0101026e" />
    <public type="attr" name="onClick" id="0x0101026f" />
+   <public type="attr" name="targetSdkVersion" id="0x01010270" />
+   <public type="attr" name="maxSdkVersion" id="0x01010271" />
 
    <public type="anim" name="anticipate_interpolator" id="0x010a0007" />
    <public type="anim" name="overshoot_interpolator" id="0x010a0008" />
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index a60f059..237b70d 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -59,6 +59,7 @@
 import android.content.pm.Signature;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Parcel;
@@ -140,8 +141,9 @@
             Process.THREAD_PRIORITY_BACKGROUND);
     final Handler mHandler;
 
-    final int mSdkVersion = SystemProperties.getInt(
-            "ro.build.version.sdk", 0);
+    final int mSdkVersion = Build.VERSION.SDK_INT;
+    final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
+            ? null : Build.VERSION.CODENAME;
     
     final Context mContext;
     final boolean mFactoryTest;
@@ -1751,7 +1753,7 @@
         parseFlags |= mDefParseFlags;
         PackageParser pp = new PackageParser(scanFile.getPath());
         pp.setSeparateProcesses(mSeparateProcesses);
-        pp.setSdkVersion(mSdkVersion);
+        pp.setSdkVersion(mSdkVersion, mSdkCodename);
         final PackageParser.Package pkg = pp.parsePackage(scanFile,
                 destCodeFile.getAbsolutePath(), mMetrics, parseFlags);
         if (pkg == null) {
@@ -3693,7 +3695,7 @@
             parseFlags |= mDefParseFlags;
             PackageParser pp = new PackageParser(tmpPackageFile.getPath());
             pp.setSeparateProcesses(mSeparateProcesses);
-            pp.setSdkVersion(mSdkVersion);
+            pp.setSdkVersion(mSdkVersion, mSdkCodename);
             final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
                     destPackageFile.getAbsolutePath(), mMetrics, parseFlags);
             if (pkg == null) {