Add new landscape and portrait orientation features.

Updates aapt to know about these.  Also updates aapt badging to:

- No longer crash due to the change to how we match unspecified
configuration resources.
- Report the new "smallest screen" supported screen configs.
- Infer old screen size buckets based on new smallest width attrs.
- Report all of the different labels and icons in an app.

Change-Id: I7376042b817391bd070f549cebbc7f03be4635c8
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 8ac7590..223b1fa 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -343,6 +343,9 @@
     REQUIRED_ATTR = 0x0101028e,
     SCREEN_SIZE_ATTR = 0x010102ca,
     SCREEN_DENSITY_ATTR = 0x010102cb,
+    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
+    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
+    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -423,6 +426,24 @@
         return 1;
     }
 
+    // Make a dummy config for retrieving resources...  we need to supply
+    // non-default values for some configs so that we can retrieve resources
+    // in the app that don't have a default.  The most important of these is
+    // the API version because key resources like icons will have an implicit
+    // version if they are using newer config types like density.
+    ResTable_config config;
+    config.language[0] = 'e';
+    config.language[1] = 'n';
+    config.country[0] = 'U';
+    config.country[1] = 'S';
+    config.orientation = ResTable_config::ORIENTATION_PORT;
+    config.density = ResTable_config::DENSITY_MEDIUM;
+    config.sdkVersion = 10000; // Very high.
+    config.screenWidthDp = 320;
+    config.screenHeightDp = 480;
+    config.smallestScreenWidthDp = 320;
+    assets.setConfiguration(config);
+
     const ResTable& res = assets.getResources(false);
     if (&res == NULL) {
         fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
@@ -542,6 +563,19 @@
                 }
             }
         } else if (strcmp("badging", option) == 0) {
+            Vector<String8> locales;
+            res.getLocales(&locales);
+
+            Vector<ResTable_config> configs;
+            res.getConfigurations(&configs);
+            SortedVector<int> densities;
+            const size_t NC = configs.size();
+            for (size_t i=0; i<NC; i++) {
+                int dens = configs[i].density;
+                if (dens == 0) dens = 160;
+                densities.add(dens);
+            }
+
             size_t len;
             ResXMLTree::event_code_t code;
             int depth = 0;
@@ -598,6 +632,8 @@
             bool specTouchscreenFeature = false; // touchscreen-related
             bool specMultitouchFeature = false;
             bool reqDistinctMultitouchFeature = false;
+            bool specScreenPortraitFeature = false;
+            bool specScreenLandscapeFeature = false;
             // 2.2 also added some other features that apps can request, but that
             // have no corresponding permission, so we cannot implement any
             // back-compatibility heuristic for them. The below are thus unnecessary
@@ -614,6 +650,9 @@
             int largeScreen = 1;
             int xlargeScreen = 1;
             int anyDensity = 1;
+            int requiresSmallestWidthDp = 0;
+            int compatibleWidthLimitDp = 0;
+            int largestWidthLimitDp = 0;
             String8 pkg;
             String8 activityName;
             String8 activityLabel;
@@ -628,10 +667,11 @@
                     } else if (depth < 3) {
                         if (withinActivity && isMainActivity && isLauncherActivity) {
                             const char *aName = getComponentName(pkg, activityName);
+                            printf("launchable-activity:");
                             if (aName != NULL) {
-                                printf("launchable activity name='%s'", aName);
+                                printf(" name='%s' ", aName);
                             }
-                            printf("label='%s' icon='%s'\n",
+                            printf(" label='%s' icon='%s'\n",
                                     activityLabel.string(),
                                     activityIcon.string());
                         }
@@ -696,23 +736,51 @@
                     withinApplication = false;
                     if (tag == "application") {
                         withinApplication = true;
-                        String8 label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
-                         if (error != "") {
-                             fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string());
-                             goto bail;
+
+                        String8 label;
+                        const size_t NL = locales.size();
+                        for (size_t i=0; i<NL; i++) {
+                            const char* localeStr =  locales[i].string();
+                            assets.setLocale(localeStr != NULL ? localeStr : "");
+                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
+                            if (llabel != "") {
+                                if (localeStr == NULL || strlen(localeStr) == 0) {
+                                    label = llabel;
+                                    printf("application-label:'%s'\n", llabel.string());
+                                } else {
+                                    if (label == "") {
+                                        label = llabel;
+                                    }
+                                    printf("application-label-%s:'%s'\n", localeStr,
+                                            llabel.string());
+                                }
+                            }
                         }
-                        printf("application: label='%s' ", label.string());
+
+                        ResTable_config tmpConfig = config;
+                        const size_t ND = densities.size();
+                        for (size_t i=0; i<ND; i++) {
+                            tmpConfig.density = densities[i];
+                            assets.setConfiguration(tmpConfig);
+                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
+                            if (icon != "") {
+                                printf("application-icon-%d:'%s'\n", densities[i], icon.string());
+                            }
+                        }
+                        assets.setConfiguration(config);
+
                         String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
                         if (error != "") {
                             fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
                             goto bail;
                         }
-                        printf("icon='%s'\n", icon.string());
                         int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
                         if (error != "") {
                             fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
                             goto bail;
                         }
+                        printf("application: label='%s' ", label.string());
+                        printf("icon='%s'\n", icon.string());
                         if (testOnly != 0) {
                             printf("testOnly='%d'\n", testOnly);
                         }
@@ -792,6 +860,12 @@
                                 XLARGE_SCREEN_ATTR, NULL, 1);
                         anyDensity = getIntegerAttribute(tree,
                                 ANY_DENSITY_ATTR, NULL, 1);
+                        requiresSmallestWidthDp = getIntegerAttribute(tree,
+                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
+                        compatibleWidthLimitDp = getIntegerAttribute(tree,
+                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
+                        largestWidthLimitDp = getIntegerAttribute(tree,
+                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
                     } else if (tag == "uses-feature") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
 
@@ -837,6 +911,10 @@
                                 // these have no corresponding permission to check for,
                                 // but should imply the foundational telephony permission
                                 reqTelephonySubFeature = true;
+                            } else if (name == "android.hardware.screen.portrait") {
+                                specScreenPortraitFeature = true;
+                            } else if (name == "android.hardware.screen.landscape") {
+                                specScreenLandscapeFeature = true;
                             }
                             printf("uses-feature%s:'%s'\n",
                                     req ? "" : "-not-required", name.string());
@@ -1103,6 +1181,15 @@
                 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
             }
 
+            // Landscape/portrait-related compatibility logic
+            if (!specScreenLandscapeFeature && !specScreenPortraitFeature && (targetSdk < 13)) {
+                // If app has not specified whether it requires portrait or landscape
+                // and is targeting an API before Honeycomb MR2, then assume it requires
+                // both.
+                printf("uses-feature:'android.hardware.screen.portrait'\n");
+                printf("uses-feature:'android.hardware.screen.landscape'\n");
+            }
+
             if (hasMainActivity) {
                 printf("main\n");
             }
@@ -1128,6 +1215,34 @@
                 printf("other-services\n");
             }
 
+            // For modern apps, if screen size buckets haven't been specified
+            // but the new width ranges have, then infer the buckets from them.
+            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
+                    && requiresSmallestWidthDp > 0) {
+                int compatWidth = compatibleWidthLimitDp;
+                if (compatWidth <= 0) compatWidth = requiresSmallestWidthDp;
+                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
+                    smallScreen = -1;
+                } else {
+                    smallScreen = 0;
+                }
+                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
+                    normalScreen = -1;
+                } else {
+                    normalScreen = 0;
+                }
+                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
+                    largeScreen = -1;
+                } else {
+                    largeScreen = 0;
+                }
+                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
+                    xlargeScreen = -1;
+                } else {
+                    xlargeScreen = 0;
+                }
+            }
+
             // Determine default values for any unspecified screen sizes,
             // based on the target SDK of the package.  As of 4 (donut)
             // the screen size support was introduced, so all default to
@@ -1146,7 +1261,8 @@
                 xlargeScreen = targetSdk >= 9 ? -1 : 0;
             }
             if (anyDensity > 0) {
-                anyDensity = targetSdk >= 4 ? -1 : 0;
+                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
+                        || compatibleWidthLimitDp > 0) ? -1 : 0;
             }
             printf("supports-screens:");
             if (smallScreen != 0) printf(" 'small'");
@@ -1154,12 +1270,18 @@
             if (largeScreen != 0) printf(" 'large'");
             if (xlargeScreen != 0) printf(" 'xlarge'");
             printf("\n");
-
             printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
+            if (requiresSmallestWidthDp > 0) {
+                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
+            }
+            if (compatibleWidthLimitDp > 0) {
+                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
+            }
+            if (largestWidthLimitDp > 0) {
+                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
+            }
 
             printf("locales:");
-            Vector<String8> locales;
-            res.getLocales(&locales);
             const size_t NL = locales.size();
             for (size_t i=0; i<NL; i++) {
                 const char* localeStr =  locales[i].string();
@@ -1170,16 +1292,6 @@
             }
             printf("\n");
 
-            Vector<ResTable_config> configs;
-            res.getConfigurations(&configs);
-            SortedVector<int> densities;
-            const size_t NC = configs.size();
-            for (size_t i=0; i<NC; i++) {
-                int dens = configs[i].density;
-                if (dens == 0) dens = 160;
-                densities.add(dens);
-            }
-
             printf("densities:");
             const size_t ND = densities.size();
             for (size_t i=0; i<ND; i++) {