Fix issue #2448075: aapt doesn't fix up activity-alias android:targetActivity links

And related:

- The aapt tool now sets a resource configurations sdk level to match any configs
  that have been set (for example if you specify density your sdk level will be
  at least 4).
- New option to modify the targetPackage attribute of instrumentation.
- Clean up of aapt options help.
- Fix of UI type values to leave 0 for "unspecified".
- Make the UI mode config APIs public.
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 69b2207..6e7a66d 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1133,6 +1133,26 @@
     getNavigationName(navigation.string(), &params);
     getScreenSizeName(screenSize.string(), &params);
     getVersionName(version.string(), &params);
+    
+    // Fix up version number based on specified parameters.
+    int minSdk = 0;
+    if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
+                != ResTable_config::UI_MODE_TYPE_ANY
+            ||  (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
+                != ResTable_config::UI_MODE_NIGHT_ANY) {
+        minSdk = SDK_FROYO;
+    } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
+                != ResTable_config::SCREENSIZE_ANY
+            ||  (params.screenLayout&ResTable_config::MASK_SCREENLONG)
+                != ResTable_config::SCREENLONG_ANY
+            || params.density != ResTable_config::DENSITY_DEFAULT) {
+        minSdk = SDK_DONUT;
+    }
+    
+    if (minSdk > params.sdkVersion) {
+        params.sdkVersion = minSdk;
+    }
+    
     return params;
 }
 
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 9a848e4..eeb00c0 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -45,6 +45,15 @@
     AXIS_VERSION
 };
 
+enum {
+    SDK_CUPCAKE = 3,
+    SDK_DONUT = 4,
+    SDK_ECLAIR = 5,
+    SDK_ECLAIR_0_1 = 6,
+    SDK_MR1 = 7,
+    SDK_FROYO = 8,
+};
+
 /**
  * This structure contains a specific variation of a single file out
  * of all the variations it can have that we can have.
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 558b587..08530a0 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -38,7 +38,8 @@
           mUpdate(false), mExtending(false),
           mRequireLocalization(false), mPseudolocalize(false),
           mUTF8(false), mEncodingSpecified(false), mValues(false),
-          mCompressionMethod(0), mOutputAPKFile(NULL), mManifestPackageNameOverride(NULL),
+          mCompressionMethod(0), mOutputAPKFile(NULL),
+          mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
           mAutoAddOverlay(false), mAssetSourceDir(NULL), mProguardFile(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL),
@@ -90,6 +91,8 @@
     void setOutputAPKFile(const char* val) { mOutputAPKFile = val; }
     const char* getManifestPackageNameOverride() const { return mManifestPackageNameOverride; }
     void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
+    const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
+    void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; }
     bool getAutoAddOverlay() { return mAutoAddOverlay; }
     void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
 
@@ -183,6 +186,7 @@
     bool        mJunkPath;
     const char* mOutputAPKFile;
     const char* mManifestPackageNameOverride;
+    const char* mInstrumentationPackageNameOverride;
     bool        mAutoAddOverlay;
     const char* mAssetSourceDir;
     const char* mProguardFile;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index ee07415..537ae5e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -525,6 +525,8 @@
             bool actWallpaperService = false;
             bool specCameraFeature = false;
             bool hasCameraPermission = false;
+            bool specGpsFeature = false;
+            bool hasGpsPermission = false;
             int targetSdk = 0;
             int smallScreen = 1;
             int normalScreen = 1;
@@ -719,6 +721,8 @@
                                     REQUIRED_ATTR, NULL, 1);
                             if (name == "android.hardware.camera") {
                                 specCameraFeature = true;
+                            } else if (name == "android.hardware.location.gps") {
+                                specGpsFeature = true;
                             }
                             printf("uses-feature%s:'%s'\n",
                                     req ? "" : "-not-required", name.string());
@@ -734,6 +738,8 @@
                         if (name != "" && error == "") {
                             if (name == "android.permission.CAMERA") {
                                 hasCameraPermission = true;
+                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
+                                hasGpsPermission = true;
                             }
                             printf("uses-permission:'%s'\n", name.string());
                         } else {
@@ -859,6 +865,14 @@
                 printf("uses-feature:'android.hardware.camera.autofocus'\n");
             }
 
+            if (!specGpsFeature && hasGpsPermission) {
+                // For applications that have not explicitly stated their
+                // GPS feature requirements, but have requested the "fine" (GPS)
+                // permission, we are going to give them compatibility treatment
+                // of requiring the equivalent to original android devices.
+                printf("uses-feature:'android.hardware.location.gps'\n");
+            }
+
             if (hasMainActivity) {
                 printf("main\n");
             }
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 6d0a351..dd98c85 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -58,9 +58,10 @@
         " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\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] [--custom-package VAL] [--utf16] \\\n"
-        "        [--auto-add-overlay] \\\n"
+        "        [--app-version VAL] [--app-version-name TEXT] [--custom-package VAL] \\\n"
+        "        [--rename-manifest-package PACKAGE] \\\n"
+        "        [--rename-instrumentation-target-package PACKAGE] \\\n"
+        "        [--utf16] [--auto-add-overlay] \\\n"
         "        [-I base-package [-I base-package ...]] \\\n"
         "        [-A asset-source-dir]  [-G class-list-file] [-P public-definitions-file] \\\n"
         "        [-S resource-sources [-S resource-sources ...]] "
@@ -127,8 +128,6 @@
         "       higher, the default encoding for resources will be in UTF-8.\n"
         "   --target-sdk-version\n"
         "       inserts android:targetSdkVersion in to manifest.\n"
-        "   --max-sdk-version\n"
-        "       inserts android:maxSdkVersion in to manifest.\n"
         "   --values\n"
         "       when used with \"dump resources\" also includes resource values.\n"
         "   --version-code\n"
@@ -139,6 +138,16 @@
         "       generates R.java into a different package.\n"
         "   --auto-add-overlay\n"
         "       Automatically add resources that are only in overlays.\n"
+        "   --rename-manifest-package\n"
+        "       Rewrite the manifest so that its package name is the package name\n"
+        "       given here.  Relative class names (for example .Foo) will be\n"
+        "       changed to absolute names with the old package so that the code\n"
+        "       does not need to change.\n"
+        "   --rename-instrumentation-target-package\n"
+        "       Rewrite the manifest so that all of its instrumentation\n"
+        "       components target the given package.  Useful when used in\n"
+        "       conjunction with --rename-manifest-package to fix tests against\n"
+        "       a package that has been renamed.\n"
         "   --utf16\n"
         "       changes default encoding for resources to UTF-16.  Only useful when API\n"
         "       level is set to 7 or higher where the default encoding is UTF-8.\n");
@@ -448,6 +457,15 @@
                         goto bail;
                     }
                     bundle.setManifestPackageNameOverride(argv[0]);
+                } else if (strcmp(cp, "-rename-instrumentation-target-package") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--rename-instrumentation-target-package' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setInstrumentationPackageNameOverride(argv[0]);
                 } else if (strcmp(cp, "-auto-add-overlay") == 0) {
                     bundle.setAutoAddOverlay(true);
                 } else {
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index ae4bd14..7142b1c 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -562,9 +562,10 @@
     node->addAttribute(ns, attr, String16(value));
 }
 
-static void fullyQualifyClassName(String8& package, sp<XMLNode> node) {
+static void fullyQualifyClassName(const String8& package, sp<XMLNode> node,
+        const String16& attrName) {
     XMLNode::attribute_entry* attr = node->editAttribute(
-            String16("http://schemas.android.com/apk/res/android"), String16("name"));
+            String16("http://schemas.android.com/apk/res/android"), attrName);
     if (attr != NULL) {
         String8 name(attr->string);
 
@@ -635,19 +636,40 @@
         // Make class names fully qualified
         sp<XMLNode> application = root->getChildElement(String16(), String16("application"));
         if (application != NULL) {
-            fullyQualifyClassName(origPackage, application);
+            fullyQualifyClassName(origPackage, application, String16("name"));
 
             Vector<sp<XMLNode> >& children = const_cast<Vector<sp<XMLNode> >&>(application->getChildren());
             for (size_t i = 0; i < children.size(); i++) {
                 sp<XMLNode> child = children.editItemAt(i);
                 String8 tag(child->getElementName());
                 if (tag == "activity" || tag == "service" || tag == "receiver" || tag == "provider") {
-                    fullyQualifyClassName(origPackage, child);
+                    fullyQualifyClassName(origPackage, child, String16("name"));
+                } else if (tag == "activity-alias") {
+                    fullyQualifyClassName(origPackage, child, String16("name"));
+                    fullyQualifyClassName(origPackage, child, String16("targetActivity"));
                 }
             }
         }
     }
 
+    // Deal with manifest package name overrides
+    const char* instrumentationPackageNameOverride = bundle->getInstrumentationPackageNameOverride();
+    if (instrumentationPackageNameOverride != NULL) {
+        // Fix up instrumentation targets.
+        Vector<sp<XMLNode> >& children = const_cast<Vector<sp<XMLNode> >&>(root->getChildren());
+        for (size_t i = 0; i < children.size(); i++) {
+            sp<XMLNode> child = children.editItemAt(i);
+            String8 tag(child->getElementName());
+            if (tag == "instrumentation") {
+                XMLNode::attribute_entry* attr = child->editAttribute(
+                        String16("http://schemas.android.com/apk/res/android"), String16("targetPackage"));
+                if (attr != NULL) {
+                    attr->string.setTo(String16(instrumentationPackageNameOverride));
+                }
+            }
+        }
+    }
+    
     return NO_ERROR;
 }