Add platform infrastructure for features.

This introduces a new mechanism to define features associated with
a platform, query the current device for the available features,
and enforce that apps requiring features that aren't available can't
be installed.

Also now allows uses-library to specify that a library is optional,
so the lack of such a library will not prevent the app from being
installed (but if it does exist it will be correctly linked into
the app).

Change-Id: I5b369b46cfa0b3d37c9e08fd14ef1098a978e67b
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 96c9486..4399df4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -184,9 +184,12 @@
             int N = p.configPreferences.size();
             if (N > 0) {
                 pi.configPreferences = new ConfigurationInfo[N];
-                for (int i=0; i<N; i++) {
-                    pi.configPreferences[i] = p.configPreferences.get(i);
-                }
+                p.configPreferences.toArray(pi.configPreferences);
+            }
+            N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
+            if (N > 0) {
+                pi.reqFeatures = new FeatureInfo[N];
+                p.reqFeatures.toArray(pi.reqFeatures);
             }
         }
         if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
@@ -760,14 +763,32 @@
                 XmlUtils.skipCurrentTag(parser);
 
             } else if (tagName.equals("uses-feature")) {
-                ConfigurationInfo cPref = new ConfigurationInfo();
+                FeatureInfo fi = new FeatureInfo();
                 sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestUsesFeature);
-                cPref.reqGlEsVersion = sa.getInt(
-                        com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
-                        ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
+                fi.name = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
+                if (fi.name == null) {
+                    fi.reqGlEsVersion = sa.getInt(
+                            com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
+                            FeatureInfo.GL_ES_VERSION_UNDEFINED);
+                }
+                if (sa.getBoolean(
+                        com.android.internal.R.styleable.AndroidManifestUsesFeature_required,
+                        true)) {
+                    fi.flags |= FeatureInfo.FLAG_REQUIRED;
+                }
                 sa.recycle();
-                pkg.configPreferences.add(cPref);
+                if (pkg.reqFeatures == null) {
+                    pkg.reqFeatures = new ArrayList<FeatureInfo>();
+                }
+                pkg.reqFeatures.add(fi);
+                
+                if (fi.name == null) {
+                    ConfigurationInfo cPref = new ConfigurationInfo();
+                    cPref.reqGlEsVersion = fi.reqGlEsVersion;
+                    pkg.configPreferences.add(cPref);
+                }
 
                 XmlUtils.skipCurrentTag(parser);
 
@@ -946,11 +967,6 @@
             }
         }
         
-        if (pkg.usesLibraries.size() > 0) {
-            pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()];
-            pkg.usesLibraries.toArray(pkg.usesLibraryFiles);
-        }
-        
         if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
                 && pkg.applicationInfo.targetSdkVersion
                         >= android.os.Build.VERSION_CODES.DONUT)) {
@@ -1436,11 +1452,28 @@
 
                 String lname = sa.getNonResourceString(
                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
+                boolean req = sa.getBoolean(
+                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
+                        true);
 
                 sa.recycle();
 
-                if (lname != null && !owner.usesLibraries.contains(lname)) {
-                    owner.usesLibraries.add(lname.intern());
+                if (lname != null) {
+                    if (req) {
+                        if (owner.usesLibraries == null) {
+                            owner.usesLibraries = new ArrayList<String>();
+                        }
+                        if (!owner.usesLibraries.contains(lname)) {
+                            owner.usesLibraries.add(lname.intern());
+                        }
+                    } else {
+                        if (owner.usesOptionalLibraries == null) {
+                            owner.usesOptionalLibraries = new ArrayList<String>();
+                        }
+                        if (!owner.usesOptionalLibraries.contains(lname)) {
+                            owner.usesOptionalLibraries.add(lname.intern());
+                        }
+                    }
                 }
 
                 XmlUtils.skipCurrentTag(parser);
@@ -2418,7 +2451,8 @@
 
         public ArrayList<String> protectedBroadcasts;
         
-        public final ArrayList<String> usesLibraries = new ArrayList<String>();
+        public ArrayList<String> usesLibraries = null;
+        public ArrayList<String> usesOptionalLibraries = null;
         public String[] usesLibraryFiles = null;
 
         // We store the application meta-data independently to avoid multiple unwanted references
@@ -2466,6 +2500,11 @@
         public final ArrayList<ConfigurationInfo> configPreferences =
                 new ArrayList<ConfigurationInfo>();
 
+        /*
+         *  Applications requested features
+         */
+        public ArrayList<FeatureInfo> reqFeatures = null;
+
         public Package(String _name) {
             packageName = _name;
             applicationInfo.packageName = _name;