return value.data;
}
+static int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
+ uint32_t attrRes, String8* outError, int32_t defValue = -1)
+{
+ ssize_t idx = indexOfAttribute(tree, attrRes);
+ if (idx < 0) {
+ return defValue;
+ }
+ Res_value value;
+ if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
+ if (value.dataType == Res_value::TYPE_REFERENCE) {
+ resTable->resolveReference(&value, 0);
+ }
+ if (value.dataType < Res_value::TYPE_FIRST_INT
+ || value.dataType > Res_value::TYPE_LAST_INT) {
+ if (outError != NULL) *outError = "attribute is not an integer value";
+ return defValue;
+ }
+ }
+ return value.data;
+}
+
static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
uint32_t attrRes, String8* outError)
{
// These are attribute resource constants for the platform, as found
// in android.R.attr
enum {
+ LABEL_ATTR = 0x01010001,
+ ICON_ATTR = 0x01010002,
NAME_ATTR = 0x01010003,
VERSION_CODE_ATTR = 0x0101021b,
VERSION_NAME_ATTR = 0x0101021c,
- LABEL_ATTR = 0x01010001,
- ICON_ATTR = 0x01010002,
+ SCREEN_ORIENTATION_ATTR = 0x0101001e,
MIN_SDK_VERSION_ATTR = 0x0101020c,
MAX_SDK_VERSION_ATTR = 0x01010271,
REQ_TOUCH_SCREEN_ATTR = 0x01010227,
REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
TARGET_SDK_VERSION_ATTR = 0x01010270,
TEST_ONLY_ATTR = 0x01010272,
- DENSITY_ATTR = 0x0101026c,
+ ANY_DENSITY_ATTR = 0x0101026c,
GL_ES_VERSION_ATTR = 0x01010281,
SMALL_SCREEN_ATTR = 0x01010284,
NORMAL_SCREEN_ATTR = 0x01010285,
LARGE_SCREEN_ATTR = 0x01010286,
XLARGE_SCREEN_ATTR = 0x010102bf,
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) {
return retStr.string();
}
+static void printCompatibleScreens(ResXMLTree& tree) {
+ size_t len;
+ ResXMLTree::event_code_t code;
+ int depth = 0;
+ bool first = true;
+ printf("compatible-screens:");
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code == ResXMLTree::END_TAG) {
+ depth--;
+ if (depth < 0) {
+ break;
+ }
+ continue;
+ }
+ if (code != ResXMLTree::START_TAG) {
+ continue;
+ }
+ depth++;
+ String8 tag(tree.getElementName(&len));
+ if (tag == "screen") {
+ int32_t screenSize = getIntegerAttribute(tree,
+ SCREEN_SIZE_ATTR, NULL, -1);
+ int32_t screenDensity = getIntegerAttribute(tree,
+ SCREEN_DENSITY_ATTR, NULL, -1);
+ if (screenSize > 0 && screenDensity > 0) {
+ if (!first) {
+ printf(",");
+ }
+ first = false;
+ printf("'%d/%d'", screenSize, screenDensity);
+ }
+ }
+ }
+ printf("\n");
+}
+
/*
* Handle the "dump" command, to extract select data from an archive.
*/
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");
}
}
} 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;
bool specTouchscreenFeature = false; // touchscreen-related
bool specMultitouchFeature = false;
bool reqDistinctMultitouchFeature = false;
+ bool specScreenPortraitFeature = false;
+ bool specScreenLandscapeFeature = false;
+ bool reqScreenPortraitFeature = false;
+ bool reqScreenLandscapeFeature = 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
int normalScreen = 1;
int largeScreen = 1;
int xlargeScreen = 1;
+ int anyDensity = 1;
+ int requiresSmallestWidthDp = 0;
+ int compatibleWidthLimitDp = 0;
+ int largestWidthLimitDp = 0;
String8 pkg;
String8 activityName;
String8 activityLabel;
} 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());
}
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);
}
printf(" reqFiveWayNav='%d'", reqFiveWayNav);
}
printf("\n");
- } else if (tag == "supports-density") {
- int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n",
- error.string());
- goto bail;
- }
- printf("supports-density:'%d'\n", dens);
} else if (tag == "supports-screens") {
smallScreen = getIntegerAttribute(tree,
SMALL_SCREEN_ATTR, NULL, 1);
LARGE_SCREEN_ATTR, NULL, 1);
xlargeScreen = getIntegerAttribute(tree,
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);
// 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());
error.string());
goto bail;
}
+ } else if (tag == "uses-package") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+ if (name != "" && error == "") {
+ printf("uses-package:'%s'\n", name.string());
+ } else {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
} else if (tag == "original-package") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
error.string());
goto bail;
}
+ } else if (tag == "supports-gl-texture") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+ if (name != "" && error == "") {
+ printf("supports-gl-texture:'%s'\n", name.string());
+ } else {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
+ } else if (tag == "compatible-screens") {
+ printCompatibleScreens(tree);
+ depth--;
}
} else if (depth == 3 && withinApplication) {
withinActivity = false;
fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
goto bail;
}
+
+ int32_t orien = getResolvedIntegerAttribute(&res, tree,
+ SCREEN_ORIENTATION_ATTR, &error);
+ if (error == "") {
+ if (orien == 0 || orien == 6 || orien == 8) {
+ // Requests landscape, sensorLandscape, or reverseLandscape.
+ reqScreenLandscapeFeature = true;
+ } else if (orien == 1 || orien == 7 || orien == 9) {
+ // Requests portrait, sensorPortrait, or reversePortrait.
+ reqScreenPortraitFeature = true;
+ }
+ }
} else if (tag == "uses-library") {
String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
}
+ // Landscape/portrait-related compatibility logic
+ if (!specScreenLandscapeFeature && !specScreenPortraitFeature) {
+ // If the app has specified any activities in its manifest
+ // that request a specific orientation, then assume that
+ // orientation is required.
+ if (reqScreenLandscapeFeature) {
+ printf("uses-feature:'android.hardware.screen.landscape'\n");
+ }
+ if (reqScreenPortraitFeature) {
+ printf("uses-feature:'android.hardware.screen.portrait'\n");
+ }
+ }
+
if (hasMainActivity) {
printf("main\n");
}
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
largeScreen = targetSdk >= 4 ? -1 : 0;
}
if (xlargeScreen > 0) {
- // Introduced in Honeycomb.
- xlargeScreen = targetSdk >= 10 ? -1 : 0;
+ // Introduced in Gingerbread.
+ xlargeScreen = targetSdk >= 9 ? -1 : 0;
+ }
+ if (anyDensity > 0) {
+ anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
+ || compatibleWidthLimitDp > 0) ? -1 : 0;
}
printf("supports-screens:");
if (smallScreen != 0) printf(" 'small'");
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();
}
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++) {