summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt/AaptAssets.cpp1523
-rw-r--r--tools/aapt/AaptAssets.h102
-rw-r--r--tools/aapt/AaptConfig.cpp790
-rw-r--r--tools/aapt/AaptConfig.h85
-rw-r--r--tools/aapt/AaptUtil.cpp64
-rw-r--r--tools/aapt/AaptUtil.h30
-rw-r--r--tools/aapt/Android.mk190
-rw-r--r--tools/aapt/ApkBuilder.cpp111
-rw-r--r--tools/aapt/ApkBuilder.h117
-rw-r--r--tools/aapt/Bundle.h34
-rw-r--r--tools/aapt/Command.cpp488
-rw-r--r--tools/aapt/ConfigDescription.h57
-rw-r--r--tools/aapt/Images.cpp12
-rw-r--r--tools/aapt/Main.cpp49
-rw-r--r--tools/aapt/Main.h16
-rw-r--r--tools/aapt/OutputSet.h56
-rw-r--r--tools/aapt/Package.cpp91
-rw-r--r--tools/aapt/Resource.cpp227
-rw-r--r--tools/aapt/ResourceFilter.cpp145
-rw-r--r--tools/aapt/ResourceFilter.h132
-rw-r--r--tools/aapt/ResourceIdCache.cpp8
-rw-r--r--tools/aapt/ResourceIdCache.h14
-rw-r--r--tools/aapt/ResourceTable.cpp106
-rw-r--r--tools/aapt/ResourceTable.h39
-rw-r--r--tools/aapt/printapk.cpp4
-rw-r--r--tools/aapt/tests/AaptConfig_test.cpp78
-rw-r--r--tools/aapt/tests/AaptGroupEntry_test.cpp54
-rw-r--r--tools/aapt/tests/ResourceFilter_test.cpp128
-rw-r--r--tools/aapt/tests/TestHelper.h33
-rw-r--r--tools/aidl/aidl.cpp14
-rw-r--r--tools/layoutlib/bridge/.classpath4
-rw-r--r--tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java50
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeResources.java6
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java25
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java37
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java4
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java6
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java6
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java183
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java38
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java29
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java7
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java1
-rw-r--r--tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java (renamed from tools/layoutlib/bridge/src/android/os/Build_Delegate.java)23
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java5
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java43
-rw-r--r--tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java22
-rw-r--r--tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java1
-rw-r--r--tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilderAccessor.java12
-rw-r--r--tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java1
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java17
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java16
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java9
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java9
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java1
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java1
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java64
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java6
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java16
-rw-r--r--tools/layoutlib/create/.classpath2
-rw-r--r--tools/layoutlib/create/README.txt266
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java11
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java3
-rw-r--r--tools/layoutlib/rename_font/README9
-rw-r--r--tools/layoutlib/rename_font/Roboto-Regular.ttfbin0 -> 114976 bytes
-rwxr-xr-xtools/layoutlib/rename_font/build_font.py121
-rwxr-xr-xtools/layoutlib/rename_font/test.py44
73 files changed, 3418 insertions, 2567 deletions
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 1f17316..12d5389 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -3,8 +3,10 @@
//
#include "AaptAssets.h"
-#include "ResourceFilter.h"
+#include "AaptConfig.h"
+#include "AaptUtil.h"
#include "Main.h"
+#include "ResourceFilter.h"
#include <utils/misc.h>
#include <utils/SortedVector.h>
@@ -14,7 +16,6 @@
#include <errno.h>
static const char* kDefaultLocale = "default";
-static const char* kWildcardName = "any";
static const char* kAssetDir = "assets";
static const char* kResourceDir = "res";
static const char* kValuesDir = "values";
@@ -149,24 +150,6 @@ static bool isHidden(const char *root, const char *path)
// =========================================================================
// =========================================================================
-/* static */ void AaptLocaleValue::splitAndLowerCase(const char* const chars,
- Vector<String8>* parts, const char separator) {
- const char *p = chars;
- const char *q;
- while (NULL != (q = strchr(p, separator))) {
- String8 val(p, q - p);
- val.toLower();
- parts->add(val);
- p = q+1;
- }
-
- if (p < chars + strlen(chars)) {
- String8 val(p);
- val.toLower();
- parts->add(val);
- }
-}
-
/* static */
inline bool isAlpha(const String8& string) {
const size_t length = string.length();
@@ -230,8 +213,7 @@ void AaptLocaleValue::setVariant(const char* variantChars) {
bool AaptLocaleValue::initFromFilterString(const String8& str) {
// A locale (as specified in the filter) is an underscore separated name such
// as "en_US", "en_Latn_US", or "en_US_POSIX".
- Vector<String8> parts;
- splitAndLowerCase(str.string(), &parts, '_');
+ Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '_');
const int numTags = parts.size();
bool valid = false;
@@ -301,8 +283,7 @@ int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int sta
if (part[0] == 'b' && part[1] == '+') {
// This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
// except that the separator is "+" and not "-".
- Vector<String8> subtags;
- AaptLocaleValue::splitAndLowerCase(part.string(), &subtags, '+');
+ Vector<String8> subtags = AaptUtil::splitAndLowerCase(part, '+');
subtags.removeItemsAt(0);
if (subtags.size() == 1) {
setLanguage(subtags[0]);
@@ -438,1349 +419,46 @@ void AaptLocaleValue::writeTo(ResTable_config* out) const {
}
}
-
-/* static */ bool
-AaptGroupEntry::parseFilterNamePart(const String8& part, int* axis, AxisValue* value)
-{
- ResTable_config config;
- memset(&config, 0, sizeof(ResTable_config));
-
- // IMSI - MCC
- if (getMccName(part.string(), &config)) {
- *axis = AXIS_MCC;
- value->intValue = config.mcc;
- return true;
- }
-
- // IMSI - MNC
- if (getMncName(part.string(), &config)) {
- *axis = AXIS_MNC;
- value->intValue = config.mnc;
- return true;
- }
-
- // locale - language
- if (value->localeValue.initFromFilterString(part)) {
- *axis = AXIS_LOCALE;
- return true;
- }
-
- // layout direction
- if (getLayoutDirectionName(part.string(), &config)) {
- *axis = AXIS_LAYOUTDIR;
- value->intValue = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
- return true;
- }
-
- // smallest screen dp width
- if (getSmallestScreenWidthDpName(part.string(), &config)) {
- *axis = AXIS_SMALLESTSCREENWIDTHDP;
- value->intValue = config.smallestScreenWidthDp;
- return true;
- }
-
- // screen dp width
- if (getScreenWidthDpName(part.string(), &config)) {
- *axis = AXIS_SCREENWIDTHDP;
- value->intValue = config.screenWidthDp;
- return true;
- }
-
- // screen dp height
- if (getScreenHeightDpName(part.string(), &config)) {
- *axis = AXIS_SCREENHEIGHTDP;
- value->intValue = config.screenHeightDp;
- return true;
- }
-
- // screen layout size
- if (getScreenLayoutSizeName(part.string(), &config)) {
- *axis = AXIS_SCREENLAYOUTSIZE;
- value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
- return true;
- }
-
- // screen layout long
- if (getScreenLayoutLongName(part.string(), &config)) {
- *axis = AXIS_SCREENLAYOUTLONG;
- value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
- return true;
- }
-
- // orientation
- if (getOrientationName(part.string(), &config)) {
- *axis = AXIS_ORIENTATION;
- value->intValue = config.orientation;
- return true;
- }
-
- // ui mode type
- if (getUiModeTypeName(part.string(), &config)) {
- *axis = AXIS_UIMODETYPE;
- value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
- return true;
- }
-
- // ui mode night
- if (getUiModeNightName(part.string(), &config)) {
- *axis = AXIS_UIMODENIGHT;
- value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
- return true;
- }
-
- // density
- if (getDensityName(part.string(), &config)) {
- *axis = AXIS_DENSITY;
- value->intValue = config.density;
- return true;
- }
-
- // touchscreen
- if (getTouchscreenName(part.string(), &config)) {
- *axis = AXIS_TOUCHSCREEN;
- value->intValue = config.touchscreen;
- return true;
- }
-
- // keyboard hidden
- if (getKeysHiddenName(part.string(), &config)) {
- *axis = AXIS_KEYSHIDDEN;
- value->intValue = config.inputFlags;
- return true;
- }
-
- // keyboard
- if (getKeyboardName(part.string(), &config)) {
- *axis = AXIS_KEYBOARD;
- value->intValue = config.keyboard;
- return true;
- }
-
- // navigation hidden
- if (getNavHiddenName(part.string(), &config)) {
- *axis = AXIS_NAVHIDDEN;
- value->intValue = config.inputFlags;
- return 0;
- }
-
- // navigation
- if (getNavigationName(part.string(), &config)) {
- *axis = AXIS_NAVIGATION;
- value->intValue = config.navigation;
- return true;
- }
-
- // screen size
- if (getScreenSizeName(part.string(), &config)) {
- *axis = AXIS_SCREENSIZE;
- value->intValue = config.screenSize;
- return true;
- }
-
- // version
- if (getVersionName(part.string(), &config)) {
- *axis = AXIS_VERSION;
- value->intValue = config.version;
- return true;
- }
-
- return false;
-}
-
-AxisValue
-AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
-{
- AxisValue value;
- switch (axis) {
- case AXIS_MCC:
- value.intValue = config.mcc;
- break;
- case AXIS_MNC:
- value.intValue = config.mnc;
- break;
- case AXIS_LOCALE:
- value.localeValue.initFromResTable(config);
- break;
- case AXIS_LAYOUTDIR:
- value.intValue = config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
- break;
- case AXIS_SCREENLAYOUTSIZE:
- value.intValue = config.screenLayout&ResTable_config::MASK_SCREENSIZE;
- break;
- case AXIS_ORIENTATION:
- value.intValue = config.orientation;
- break;
- case AXIS_UIMODETYPE:
- value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
- break;
- case AXIS_UIMODENIGHT:
- value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
- break;
- case AXIS_DENSITY:
- value.intValue = config.density;
- break;
- case AXIS_TOUCHSCREEN:
- value.intValue = config.touchscreen;
- break;
- case AXIS_KEYSHIDDEN:
- value.intValue = config.inputFlags;
- break;
- case AXIS_KEYBOARD:
- value.intValue = config.keyboard;
- break;
- case AXIS_NAVIGATION:
- value.intValue = config.navigation;
- break;
- case AXIS_SCREENSIZE:
- value.intValue = config.screenSize;
- break;
- case AXIS_SMALLESTSCREENWIDTHDP:
- value.intValue = config.smallestScreenWidthDp;
- break;
- case AXIS_SCREENWIDTHDP:
- value.intValue = config.screenWidthDp;
- break;
- case AXIS_SCREENHEIGHTDP:
- value.intValue = config.screenHeightDp;
- break;
- case AXIS_VERSION:
- value.intValue = config.version;
- break;
- }
-
- return value;
-}
-
-bool
-AaptGroupEntry::configSameExcept(const ResTable_config& config,
- const ResTable_config& otherConfig, int axis)
-{
- for (int i=AXIS_START; i<=AXIS_END; i++) {
- if (i == axis) {
- continue;
- }
- if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) {
- return false;
- }
- }
- return true;
-}
-
bool
AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
{
- mParamsChanged = true;
-
- Vector<String8> parts;
- AaptLocaleValue::splitAndLowerCase(dir, &parts, '-');
-
- String8 mcc, mnc, layoutsize, layoutlong, orient, den;
- String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
- String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
-
- AaptLocaleValue locale;
- int numLocaleComponents = 0;
-
- const int N = parts.size();
- int index = 0;
- String8 part = parts[index];
-
- // resource type
- if (!isValidResourceType(part)) {
- return false;
- }
- *resType = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
-
- // imsi - mcc
- if (getMccName(part.string())) {
- mcc = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
+ const char* q = strchr(dir, '-');
+ size_t typeLen;
+ if (q != NULL) {
+ typeLen = q - dir;
} else {
- //printf("not mcc: %s\n", part.string());
+ typeLen = strlen(dir);
}
- // imsi - mnc
- if (getMncName(part.string())) {
- mnc = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not mnc: %s\n", part.string());
- }
-
- index = locale.initFromDirName(parts, index);
- if (index == -1) {
+ String8 type(dir, typeLen);
+ if (!isValidResourceType(type)) {
return false;
}
- if (index >= N){
- goto success;
- }
-
- part = parts[index];
- if (getLayoutDirectionName(part.string())) {
- layoutDir = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not layout direction: %s\n", part.string());
- }
-
- if (getSmallestScreenWidthDpName(part.string())) {
- smallestwidthdp = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not smallest screen width dp: %s\n", part.string());
- }
-
- if (getScreenWidthDpName(part.string())) {
- widthdp = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen width dp: %s\n", part.string());
- }
-
- if (getScreenHeightDpName(part.string())) {
- heightdp = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen height dp: %s\n", part.string());
- }
-
- if (getScreenLayoutSizeName(part.string())) {
- layoutsize = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen layout size: %s\n", part.string());
- }
-
- if (getScreenLayoutLongName(part.string())) {
- layoutlong = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen layout long: %s\n", part.string());
- }
-
- // orientation
- if (getOrientationName(part.string())) {
- orient = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not orientation: %s\n", part.string());
- }
-
- // ui mode type
- if (getUiModeTypeName(part.string())) {
- uiModeType = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not ui mode type: %s\n", part.string());
- }
-
- // ui mode night
- if (getUiModeNightName(part.string())) {
- uiModeNight = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not ui mode night: %s\n", part.string());
- }
-
- // density
- if (getDensityName(part.string())) {
- den = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not density: %s\n", part.string());
- }
-
- // touchscreen
- if (getTouchscreenName(part.string())) {
- touch = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not touchscreen: %s\n", part.string());
- }
-
- // keyboard hidden
- if (getKeysHiddenName(part.string())) {
- keysHidden = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not keysHidden: %s\n", part.string());
- }
-
- // keyboard
- if (getKeyboardName(part.string())) {
- key = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not keyboard: %s\n", part.string());
- }
-
- // navigation hidden
- if (getNavHiddenName(part.string())) {
- navHidden = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not navHidden: %s\n", part.string());
- }
- if (getNavigationName(part.string())) {
- nav = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not navigation: %s\n", part.string());
- }
-
- if (getScreenSizeName(part.string())) {
- size = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen size: %s\n", part.string());
- }
-
- if (getVersionName(part.string())) {
- vers = part;
-
- index++;
- if (index == N) {
- goto success;
+ if (q != NULL) {
+ if (!AaptConfig::parse(String8(q + 1), &mParams)) {
+ return false;
}
- part = parts[index];
- } else {
- //printf("not version: %s\n", part.string());
}
- // if there are extra parts, it doesn't match
- return false;
-
-success:
- this->mcc = mcc;
- this->mnc = mnc;
- this->locale = locale;
- this->screenLayoutSize = layoutsize;
- this->screenLayoutLong = layoutlong;
- this->smallestScreenWidthDp = smallestwidthdp;
- this->screenWidthDp = widthdp;
- this->screenHeightDp = heightdp;
- this->orientation = orient;
- this->uiModeType = uiModeType;
- this->uiModeNight = uiModeNight;
- this->density = den;
- this->touchscreen = touch;
- this->keysHidden = keysHidden;
- this->keyboard = key;
- this->navHidden = navHidden;
- this->navigation = nav;
- this->screenSize = size;
- this->layoutDirection = layoutDir;
- this->version = vers;
-
- // what is this anyway?
- this->vendor = "";
-
+ *resType = type;
return true;
}
String8
-AaptGroupEntry::toString() const
-{
- String8 s = this->mcc;
- s += ",";
- s += this->mnc;
- s += ",";
- s += locale.toDirName();
- s += ",";
- s += layoutDirection;
- s += ",";
- s += smallestScreenWidthDp;
- s += ",";
- s += screenWidthDp;
- s += ",";
- s += screenHeightDp;
- s += ",";
- s += screenLayoutSize;
- s += ",";
- s += screenLayoutLong;
- s += ",";
- s += this->orientation;
- s += ",";
- s += uiModeType;
- s += ",";
- s += uiModeNight;
- s += ",";
- s += density;
- s += ",";
- s += touchscreen;
- s += ",";
- s += keysHidden;
- s += ",";
- s += keyboard;
- s += ",";
- s += navHidden;
- s += ",";
- s += navigation;
- s += ",";
- s += screenSize;
- s += ",";
- s += version;
- return s;
-}
-
-String8
AaptGroupEntry::toDirName(const String8& resType) const
{
String8 s = resType;
- if (this->mcc != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += mcc;
- }
- if (this->mnc != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += mnc;
- }
-
- const String8 localeComponent = locale.toDirName();
- if (localeComponent != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += localeComponent;
- }
-
- if (this->layoutDirection != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += layoutDirection;
- }
- if (this->smallestScreenWidthDp != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += smallestScreenWidthDp;
- }
- if (this->screenWidthDp != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenWidthDp;
- }
- if (this->screenHeightDp != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenHeightDp;
- }
- if (this->screenLayoutSize != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenLayoutSize;
- }
- if (this->screenLayoutLong != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenLayoutLong;
- }
- if (this->orientation != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += orientation;
- }
- if (this->uiModeType != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += uiModeType;
- }
- if (this->uiModeNight != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += uiModeNight;
- }
- if (this->density != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += density;
- }
- if (this->touchscreen != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += touchscreen;
- }
- if (this->keysHidden != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += keysHidden;
- }
- if (this->keyboard != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += keyboard;
- }
- if (this->navHidden != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += navHidden;
- }
- if (this->navigation != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += navigation;
- }
- if (this->screenSize != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenSize;
- }
- if (this->version != "") {
+ String8 params = mParams.toString();
+ if (params.length() > 0) {
if (s.length() > 0) {
s += "-";
}
- s += version;
+ s += params;
}
-
return s;
}
-bool AaptGroupEntry::getMccName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->mcc = 0;
- return true;
- }
- const char* c = name;
- if (tolower(*c) != 'm') return false;
- c++;
- if (tolower(*c) != 'c') return false;
- c++;
- if (tolower(*c) != 'c') return false;
- c++;
-
- const char* val = c;
-
- while (*c >= '0' && *c <= '9') {
- c++;
- }
- if (*c != 0) return false;
- if (c-val != 3) return false;
-
- int d = atoi(val);
- if (d != 0) {
- if (out) out->mcc = d;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getMncName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->mcc = 0;
- return true;
- }
- const char* c = name;
- if (tolower(*c) != 'm') return false;
- c++;
- if (tolower(*c) != 'n') return false;
- c++;
- if (tolower(*c) != 'c') return false;
- c++;
-
- const char* val = c;
-
- while (*c >= '0' && *c <= '9') {
- c++;
- }
- if (*c != 0) return false;
- if (c-val == 0 || c-val > 3) return false;
-
- if (out) {
- out->mnc = atoi(val);
- if (out->mnc == 0) {
- out->mnc = ACONFIGURATION_MNC_ZERO;
- }
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
- | ResTable_config::LAYOUTDIR_ANY;
- return true;
- } else if (strcmp(name, "ldltr") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
- | ResTable_config::LAYOUTDIR_LTR;
- return true;
- } else if (strcmp(name, "ldrtl") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
- | ResTable_config::LAYOUTDIR_RTL;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_ANY;
- return true;
- } else if (strcmp(name, "small") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_SMALL;
- return true;
- } else if (strcmp(name, "normal") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_NORMAL;
- return true;
- } else if (strcmp(name, "large") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_LARGE;
- return true;
- } else if (strcmp(name, "xlarge") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_XLARGE;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
- | ResTable_config::SCREENLONG_ANY;
- return true;
- } else if (strcmp(name, "long") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
- | ResTable_config::SCREENLONG_YES;
- return true;
- } else if (strcmp(name, "notlong") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
- | ResTable_config::SCREENLONG_NO;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getOrientationName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->orientation = out->ORIENTATION_ANY;
- return true;
- } else if (strcmp(name, "port") == 0) {
- if (out) out->orientation = out->ORIENTATION_PORT;
- return true;
- } else if (strcmp(name, "land") == 0) {
- if (out) out->orientation = out->ORIENTATION_LAND;
- return true;
- } else if (strcmp(name, "square") == 0) {
- if (out) out->orientation = out->ORIENTATION_SQUARE;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getUiModeTypeName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_ANY;
- return true;
- } else if (strcmp(name, "desk") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_DESK;
- return true;
- } else if (strcmp(name, "car") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_CAR;
- return true;
- } else if (strcmp(name, "television") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_TELEVISION;
- return true;
- } else if (strcmp(name, "appliance") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_APPLIANCE;
- return true;
- } else if (strcmp(name, "watch") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_WATCH;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getUiModeNightName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
- | ResTable_config::UI_MODE_NIGHT_ANY;
- return true;
- } else if (strcmp(name, "night") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
- | ResTable_config::UI_MODE_NIGHT_YES;
- return true;
- } else if (strcmp(name, "notnight") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
- | ResTable_config::UI_MODE_NIGHT_NO;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getDensityName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->density = ResTable_config::DENSITY_DEFAULT;
- return true;
- }
-
- if (strcmp(name, "nodpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_NONE;
- return true;
- }
-
- if (strcmp(name, "ldpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_LOW;
- return true;
- }
-
- if (strcmp(name, "mdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_MEDIUM;
- return true;
- }
-
- if (strcmp(name, "tvdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_TV;
- return true;
- }
-
- if (strcmp(name, "hdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_HIGH;
- return true;
- }
-
- if (strcmp(name, "xhdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_XHIGH;
- return true;
- }
-
- if (strcmp(name, "xxhdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_XXHIGH;
- return true;
- }
-
- if (strcmp(name, "xxxhdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
- return true;
- }
-
- char* c = (char*)name;
- while (*c >= '0' && *c <= '9') {
- c++;
- }
-
- // check that we have 'dpi' after the last digit.
- if (toupper(c[0]) != 'D' ||
- toupper(c[1]) != 'P' ||
- toupper(c[2]) != 'I' ||
- c[3] != 0) {
- return false;
- }
-
- // temporarily replace the first letter with \0 to
- // use atoi.
- char tmp = c[0];
- c[0] = '\0';
-
- int d = atoi(name);
- c[0] = tmp;
-
- if (d != 0) {
- if (out) out->density = d;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getTouchscreenName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
- return true;
- } else if (strcmp(name, "notouch") == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
- return true;
- } else if (strcmp(name, "stylus") == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
- return true;
- } else if (strcmp(name, "finger") == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getKeysHiddenName(const char* name,
- ResTable_config* out)
-{
- uint8_t mask = 0;
- uint8_t value = 0;
- if (strcmp(name, kWildcardName) == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_ANY;
- } else if (strcmp(name, "keysexposed") == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_NO;
- } else if (strcmp(name, "keyshidden") == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_YES;
- } else if (strcmp(name, "keyssoft") == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_SOFT;
- }
-
- if (mask != 0) {
- if (out) out->inputFlags = (out->inputFlags&~mask) | value;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getKeyboardName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->keyboard = out->KEYBOARD_ANY;
- return true;
- } else if (strcmp(name, "nokeys") == 0) {
- if (out) out->keyboard = out->KEYBOARD_NOKEYS;
- return true;
- } else if (strcmp(name, "qwerty") == 0) {
- if (out) out->keyboard = out->KEYBOARD_QWERTY;
- return true;
- } else if (strcmp(name, "12key") == 0) {
- if (out) out->keyboard = out->KEYBOARD_12KEY;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getNavHiddenName(const char* name,
- ResTable_config* out)
-{
- uint8_t mask = 0;
- uint8_t value = 0;
- if (strcmp(name, kWildcardName) == 0) {
- mask = ResTable_config::MASK_NAVHIDDEN;
- value = ResTable_config::NAVHIDDEN_ANY;
- } else if (strcmp(name, "navexposed") == 0) {
- mask = ResTable_config::MASK_NAVHIDDEN;
- value = ResTable_config::NAVHIDDEN_NO;
- } else if (strcmp(name, "navhidden") == 0) {
- mask = ResTable_config::MASK_NAVHIDDEN;
- value = ResTable_config::NAVHIDDEN_YES;
- }
-
- if (mask != 0) {
- if (out) out->inputFlags = (out->inputFlags&~mask) | value;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getNavigationName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->navigation = out->NAVIGATION_ANY;
- return true;
- } else if (strcmp(name, "nonav") == 0) {
- if (out) out->navigation = out->NAVIGATION_NONAV;
- return true;
- } else if (strcmp(name, "dpad") == 0) {
- if (out) out->navigation = out->NAVIGATION_DPAD;
- return true;
- } else if (strcmp(name, "trackball") == 0) {
- if (out) out->navigation = out->NAVIGATION_TRACKBALL;
- return true;
- } else if (strcmp(name, "wheel") == 0) {
- if (out) out->navigation = out->NAVIGATION_WHEEL;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->screenWidth = out->SCREENWIDTH_ANY;
- out->screenHeight = out->SCREENHEIGHT_ANY;
- }
- return true;
- }
-
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || *x != 'x') return false;
- String8 xName(name, x-name);
- x++;
-
- const char* y = x;
- while (*y >= '0' && *y <= '9') y++;
- if (y == name || *y != 0) return false;
- String8 yName(x, y-x);
-
- uint16_t w = (uint16_t)atoi(xName.string());
- uint16_t h = (uint16_t)atoi(yName.string());
- if (w < h) {
- return false;
- }
-
- if (out) {
- out->screenWidth = w;
- out->screenHeight = h;
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
- }
- return true;
- }
-
- if (*name != 's') return false;
- name++;
- if (*name != 'w') return false;
- name++;
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
- String8 xName(name, x-name);
-
- if (out) {
- out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->screenWidthDp = out->SCREENWIDTH_ANY;
- }
- return true;
- }
-
- if (*name != 'w') return false;
- name++;
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
- String8 xName(name, x-name);
-
- if (out) {
- out->screenWidthDp = (uint16_t)atoi(xName.string());
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->screenHeightDp = out->SCREENWIDTH_ANY;
- }
- return true;
- }
-
- if (*name != 'h') return false;
- name++;
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
- String8 xName(name, x-name);
-
- if (out) {
- out->screenHeightDp = (uint16_t)atoi(xName.string());
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->sdkVersion = out->SDKVERSION_ANY;
- out->minorVersion = out->MINORVERSION_ANY;
- }
- return true;
- }
-
- if (*name != 'v') {
- return false;
- }
-
- name++;
- const char* s = name;
- while (*s >= '0' && *s <= '9') s++;
- if (s == name || *s != 0) return false;
- String8 sdkName(name, s-name);
-
- if (out) {
- out->sdkVersion = (uint16_t)atoi(sdkName.string());
- out->minorVersion = 0;
- }
-
- return true;
-}
-
-int AaptGroupEntry::compare(const AaptGroupEntry& o) const
-{
- int v = mcc.compare(o.mcc);
- if (v == 0) v = mnc.compare(o.mnc);
- if (v == 0) v = locale.compare(o.locale);
- if (v == 0) v = layoutDirection.compare(o.layoutDirection);
- if (v == 0) v = vendor.compare(o.vendor);
- if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
- if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
- if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
- if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
- if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
- if (v == 0) v = orientation.compare(o.orientation);
- if (v == 0) v = uiModeType.compare(o.uiModeType);
- if (v == 0) v = uiModeNight.compare(o.uiModeNight);
- if (v == 0) v = density.compare(o.density);
- if (v == 0) v = touchscreen.compare(o.touchscreen);
- if (v == 0) v = keysHidden.compare(o.keysHidden);
- if (v == 0) v = keyboard.compare(o.keyboard);
- if (v == 0) v = navHidden.compare(o.navHidden);
- if (v == 0) v = navigation.compare(o.navigation);
- if (v == 0) v = screenSize.compare(o.screenSize);
- if (v == 0) v = version.compare(o.version);
- return v;
-}
-
-const ResTable_config AaptGroupEntry::toParams() const
-{
- if (!mParamsChanged) {
- return mParams;
- }
-
- mParamsChanged = false;
- ResTable_config& params = mParams;
- memset(&params, 0, sizeof(ResTable_config));
- getMccName(mcc.string(), &params);
- getMncName(mnc.string(), &params);
- locale.writeTo(&params);
- getLayoutDirectionName(layoutDirection.string(), &params);
- getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
- getScreenWidthDpName(screenWidthDp.string(), &params);
- getScreenHeightDpName(screenHeightDp.string(), &params);
- getScreenLayoutSizeName(screenLayoutSize.string(), &params);
- getScreenLayoutLongName(screenLayoutLong.string(), &params);
- getOrientationName(orientation.string(), &params);
- getUiModeTypeName(uiModeType.string(), &params);
- getUiModeNightName(uiModeNight.string(), &params);
- getDensityName(density.string(), &params);
- getTouchscreenName(touchscreen.string(), &params);
- getKeysHiddenName(keysHidden.string(), &params);
- getKeyboardName(keyboard.string(), &params);
- getNavHiddenName(navHidden.string(), &params);
- 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.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
- || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
- || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
- minSdk = SDK_HONEYCOMB_MR2;
- } else 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;
-}
// =========================================================================
// =========================================================================
@@ -1803,6 +481,11 @@ void* AaptFile::editData(size_t size)
return buf;
}
+void* AaptFile::editDataInRange(size_t offset, size_t size)
+{
+ return (void*)(((uint8_t*) editData(offset + size)) + offset);
+}
+
void* AaptFile::editData(size_t* outSize)
{
if (outSize) {
@@ -2224,9 +907,7 @@ AaptAssets::AaptAssets()
: AaptDir(String8(), String8()),
mHavePrivateSymbols(false),
mChanged(false), mHaveIncludedAssets(false),
- mRes(NULL)
-{
-}
+ mRes(NULL) {}
const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
if (mChanged) {
@@ -2383,6 +1064,9 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
current->setFullResPaths(mFullResPaths);
}
count = current->slurpResourceTree(bundle, String8(res));
+ if (i > 0 && count > 0) {
+ count = current->filter(bundle);
+ }
if (count < 0) {
totalCount = count;
@@ -2498,7 +1182,7 @@ ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
String8 resType;
bool b = group.initFromDirName(entry->d_name, &resType);
if (!b) {
- fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
+ fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.string(),
entry->d_name);
err = -1;
continue;
@@ -2646,30 +1330,35 @@ bail:
status_t AaptAssets::filter(Bundle* bundle)
{
- ResourceFilter reqFilter;
+ WeakResourceFilter reqFilter;
status_t err = reqFilter.parse(bundle->getConfigurations());
if (err != NO_ERROR) {
return err;
}
- ResourceFilter prefFilter;
- err = prefFilter.parse(bundle->getPreferredConfigurations());
- if (err != NO_ERROR) {
- return err;
+ uint32_t preferredDensity = 0;
+ if (bundle->getPreferredDensity().size() > 0) {
+ ResTable_config preferredConfig;
+ if (!AaptConfig::parseDensity(bundle->getPreferredDensity().string(), &preferredConfig)) {
+ fprintf(stderr, "Error parsing preferred density: %s\n",
+ bundle->getPreferredDensity().string());
+ return UNKNOWN_ERROR;
+ }
+ preferredDensity = preferredConfig.density;
}
- if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
+ if (reqFilter.isEmpty() && preferredDensity == 0) {
return NO_ERROR;
}
if (bundle->getVerbose()) {
if (!reqFilter.isEmpty()) {
printf("Applying required filter: %s\n",
- bundle->getConfigurations());
+ bundle->getConfigurations().string());
}
- if (!prefFilter.isEmpty()) {
- printf("Applying preferred filter: %s\n",
- bundle->getPreferredConfigurations());
+ if (preferredDensity > 0) {
+ printf("Applying preferred density filter: %s\n",
+ bundle->getPreferredDensity().string());
}
}
@@ -2726,88 +1415,70 @@ status_t AaptAssets::filter(Bundle* bundle)
}
// Quick check: no preferred filters, nothing more to do.
- if (prefFilter.isEmpty()) {
+ if (preferredDensity == 0) {
continue;
}
// Get the preferred density if there is one. We do not match exactly for density.
// If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
// pick xhdpi.
- uint32_t preferredDensity = 0;
- const SortedVector<AxisValue>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
- if (preferredConfigs != NULL && preferredConfigs->size() > 0) {
- preferredDensity = (*preferredConfigs)[0].intValue;
- }
+ for (size_t k=0; k<grp->getFiles().size(); k++) {
+ sp<AaptFile> file = grp->getFiles().valueAt(k);
+ if (k == 0 && grp->getFiles().size() == 1) {
+ // If this is the only file left, we need to keep it.
+ // Otherwise the resource IDs we are using will be inconsistent
+ // with what we get when not stripping. Sucky, but at least
+ // for now we can rely on the back-end doing another filtering
+ // pass to take this out and leave us with this resource name
+ // containing no entries.
+ continue;
+ }
+ if (file->getPath().getPathExtension() == ".xml") {
+ // We can't remove .xml files at this point, because when
+ // we parse them they may add identifier resources, so
+ // removing them can cause our resource identifiers to
+ // become inconsistent.
+ continue;
+ }
+ const ResTable_config& config(file->getGroupEntry().toParams());
+ if (config.density != 0 && config.density != preferredDensity) {
+ // This is a resource we would prefer not to have. Check
+ // to see if have a similar variation that we would like
+ // to have and, if so, we can drop it.
+ uint32_t bestDensity = config.density;
+
+ for (size_t m=0; m<grp->getFiles().size(); m++) {
+ if (m == k) {
+ continue;
+ }
- // Now deal with preferred configurations.
- for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
- for (size_t k=0; k<grp->getFiles().size(); k++) {
- sp<AaptFile> file = grp->getFiles().valueAt(k);
- if (k == 0 && grp->getFiles().size() == 1) {
- // If this is the only file left, we need to keep it.
- // Otherwise the resource IDs we are using will be inconsistent
- // with what we get when not stripping. Sucky, but at least
- // for now we can rely on the back-end doing another filtering
- // pass to take this out and leave us with this resource name
- // containing no entries.
- continue;
- }
- if (file->getPath().getPathExtension() == ".xml") {
- // We can't remove .xml files at this point, because when
- // we parse them they may add identifier resources, so
- // removing them can cause our resource identifiers to
- // become inconsistent.
- continue;
- }
- const ResTable_config& config(file->getGroupEntry().toParams());
- if (!prefFilter.match(axis, config)) {
- // This is a resource we would prefer not to have. Check
- // to see if have a similar variation that we would like
- // to have and, if so, we can drop it.
-
- uint32_t bestDensity = config.density;
-
- for (size_t m=0; m<grp->getFiles().size(); m++) {
- if (m == k) continue;
- sp<AaptFile> mfile = grp->getFiles().valueAt(m);
- const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
- if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
- if (axis == AXIS_DENSITY && preferredDensity > 0) {
- // See if there is a better density resource
- if (mconfig.density < bestDensity &&
- mconfig.density > preferredDensity &&
- bestDensity > preferredDensity) {
- // This density is between our best density and
- // the preferred density, therefore it is better.
- bestDensity = mconfig.density;
- } else if (mconfig.density > bestDensity &&
- bestDensity < preferredDensity) {
- // This density is better than our best density and
- // our best density was smaller than our preferred
- // density, so it is better.
- bestDensity = mconfig.density;
- }
- } else if (prefFilter.match(axis, mconfig)) {
- if (bundle->getVerbose()) {
- printf("Pruning unneeded resource: %s\n",
- file->getPrintableSource().string());
- }
- grp->removeFile(k);
- k--;
- break;
- }
+ sp<AaptFile> mfile = grp->getFiles().valueAt(m);
+ const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
+ if (AaptConfig::isSameExcept(config, mconfig, ResTable_config::CONFIG_DENSITY)) {
+ // See if there is a better density resource
+ if (mconfig.density < bestDensity &&
+ mconfig.density > preferredDensity &&
+ bestDensity > preferredDensity) {
+ // This density is between our best density and
+ // the preferred density, therefore it is better.
+ bestDensity = mconfig.density;
+ } else if (mconfig.density > bestDensity &&
+ bestDensity < preferredDensity) {
+ // This density is better than our best density and
+ // our best density was smaller than our preferred
+ // density, so it is better.
+ bestDensity = mconfig.density;
}
}
+ }
- if (axis == AXIS_DENSITY && preferredDensity > 0 &&
- bestDensity != config.density) {
- if (bundle->getVerbose()) {
- printf("Pruning unneeded resource: %s\n",
- file->getPrintableSource().string());
- }
- grp->removeFile(k);
- k--;
+ if (bestDensity != config.density) {
+ if (bundle->getVerbose()) {
+ printf("Pruning unneeded resource: %s\n",
+ file->getPrintableSource().string());
}
+ grp->removeFile(k);
+ k--;
}
}
}
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 336d08b..0c2576a 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -6,22 +6,24 @@
#ifndef __AAPT_ASSETS_H
#define __AAPT_ASSETS_H
-#include <stdlib.h>
#include <androidfw/AssetManager.h>
#include <androidfw/ResourceTypes.h>
+#include <stdlib.h>
+#include <set>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
-#include "ZipFile.h"
+#include "AaptConfig.h"
#include "Bundle.h"
+#include "ConfigDescription.h"
#include "SourcePos.h"
+#include "ZipFile.h"
using namespace android;
-
extern const char * const gDefaultIgnoreAssets;
extern const char * gUserIgnoreAssets;
@@ -82,9 +84,6 @@ struct AaptLocaleValue {
return memcmp(this, &other, sizeof(AaptLocaleValue));
}
- static void splitAndLowerCase(const char* const chars, Vector<String8>* parts,
- const char separator);
-
inline bool operator<(const AaptLocaleValue& o) const { return compare(o) < 0; }
inline bool operator<=(const AaptLocaleValue& o) const { return compare(o) <= 0; }
inline bool operator==(const AaptLocaleValue& o) const { return compare(o) == 0; }
@@ -98,31 +97,6 @@ private:
void setVariant(const char* variant);
};
-struct AxisValue {
- // Used for all axes except AXIS_LOCALE, which is represented
- // as a AaptLocaleValue value.
- int intValue;
- AaptLocaleValue localeValue;
-
- AxisValue() : intValue(0) {
- }
-
- inline int compare(const AxisValue &other) const {
- if (intValue != other.intValue) {
- return intValue - other.intValue;
- }
-
- return localeValue.compare(other.localeValue);
- }
-
- inline bool operator<(const AxisValue& o) const { return compare(o) < 0; }
- inline bool operator<=(const AxisValue& o) const { return compare(o) <= 0; }
- inline bool operator==(const AxisValue& o) const { return compare(o) == 0; }
- inline bool operator!=(const AxisValue& o) const { return compare(o) != 0; }
- inline bool operator>=(const AxisValue& o) const { return compare(o) >= 0; }
- inline bool operator>(const AxisValue& o) const { return compare(o) > 0; }
-};
-
/**
* This structure contains a specific variation of a single file out
* of all the variations it can have that we can have.
@@ -130,23 +104,11 @@ struct AxisValue {
struct AaptGroupEntry
{
public:
- AaptGroupEntry() : mParamsChanged(true) {
- memset(&mParams, 0, sizeof(ResTable_config));
- }
-
bool initFromDirName(const char* dir, String8* resType);
- static bool parseFilterNamePart(const String8& part, int* axis, AxisValue* value);
-
- static AxisValue getConfigValueForAxis(const ResTable_config& config, int axis);
-
- static bool configSameExcept(const ResTable_config& config,
- const ResTable_config& otherConfig, int axis);
-
- int compare(const AaptGroupEntry& o) const;
-
- const ResTable_config toParams() const;
+ inline const ConfigDescription& toParams() const { return mParams; }
+ inline int compare(const AaptGroupEntry& o) const { return mParams.compareLogical(o.mParams); }
inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
@@ -154,56 +116,13 @@ public:
inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
- String8 toString() const;
+ String8 toString() const { return mParams.toString(); }
String8 toDirName(const String8& resType) const;
- const String8& getVersionString() const { return version; }
+ const String8 getVersionString() const { return AaptConfig::getVersion(mParams); }
private:
- static bool getMccName(const char* name, ResTable_config* out = NULL);
- static bool getMncName(const char* name, ResTable_config* out = NULL);
- static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL);
- static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL);
- static bool getOrientationName(const char* name, ResTable_config* out = NULL);
- static bool getUiModeTypeName(const char* name, ResTable_config* out = NULL);
- static bool getUiModeNightName(const char* name, ResTable_config* out = NULL);
- static bool getDensityName(const char* name, ResTable_config* out = NULL);
- static bool getTouchscreenName(const char* name, ResTable_config* out = NULL);
- static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL);
- static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
- static bool getNavigationName(const char* name, ResTable_config* out = NULL);
- static bool getNavHiddenName(const char* name, ResTable_config* out = NULL);
- static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
- static bool getSmallestScreenWidthDpName(const char* name, ResTable_config* out = NULL);
- static bool getScreenWidthDpName(const char* name, ResTable_config* out = NULL);
- static bool getScreenHeightDpName(const char* name, ResTable_config* out = NULL);
- static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL);
- static bool getVersionName(const char* name, ResTable_config* out = NULL);
-
- String8 mcc;
- String8 mnc;
- AaptLocaleValue locale;
- String8 vendor;
- String8 smallestScreenWidthDp;
- String8 screenWidthDp;
- String8 screenHeightDp;
- String8 screenLayoutSize;
- String8 screenLayoutLong;
- String8 orientation;
- String8 uiModeType;
- String8 uiModeNight;
- String8 density;
- String8 touchscreen;
- String8 keysHidden;
- String8 keyboard;
- String8 navHidden;
- String8 navigation;
- String8 screenSize;
- String8 layoutDirection;
- String8 version;
-
- mutable bool mParamsChanged;
- mutable ResTable_config mParams;
+ ConfigDescription mParams;
};
inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
@@ -251,6 +170,7 @@ public:
size_t getSize() const { return mDataSize; }
void* editData(size_t size);
void* editData(size_t* outSize = NULL);
+ void* editDataInRange(size_t offset, size_t size);
void* padData(size_t wordSize);
status_t writeData(const void* data, size_t size);
void clearData();
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
new file mode 100644
index 0000000..69a9c7f
--- /dev/null
+++ b/tools/aapt/AaptConfig.cpp
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <ctype.h>
+
+#include "AaptConfig.h"
+#include "AaptAssets.h"
+#include "AaptUtil.h"
+#include "ResourceFilter.h"
+
+using android::String8;
+using android::Vector;
+using android::ResTable_config;
+
+namespace AaptConfig {
+
+static const char* kWildcardName = "any";
+
+bool parse(const String8& str, ConfigDescription* out) {
+ Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '-');
+
+ ConfigDescription config;
+ AaptLocaleValue locale;
+ ssize_t index = 0;
+ ssize_t localeIndex = 0;
+ const ssize_t N = parts.size();
+ const char* part = parts[index].string();
+
+ if (str.length() == 0) {
+ goto success;
+ }
+
+ if (parseMcc(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseMnc(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ // Locale spans a few '-' separators, so we let it
+ // control the index.
+ localeIndex = locale.initFromDirName(parts, index);
+ if (localeIndex < 0) {
+ return false;
+ } else if (localeIndex > index) {
+ locale.writeTo(&config);
+ index = localeIndex;
+ if (index >= N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseLayoutDirection(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseSmallestScreenWidthDp(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenWidthDp(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenHeightDp(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenLayoutSize(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenLayoutLong(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseOrientation(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseUiModeType(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseUiModeNight(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseDensity(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseTouchscreen(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseKeysHidden(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseKeyboard(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseNavHidden(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseNavigation(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenSize(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseVersion(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ // Unrecognized.
+ return false;
+
+success:
+ if (out != NULL) {
+ applyVersionForCompatibility(&config);
+ *out = config;
+ }
+ return true;
+}
+
+bool parseCommaSeparatedList(const String8& str, std::set<ConfigDescription>* outSet) {
+ Vector<String8> parts = AaptUtil::splitAndLowerCase(str, ',');
+ const size_t N = parts.size();
+ for (size_t i = 0; i < N; i++) {
+ ConfigDescription config;
+ if (!parse(parts[i], &config)) {
+ return false;
+ }
+ outSet->insert(config);
+ }
+ return true;
+}
+
+void applyVersionForCompatibility(ConfigDescription* config) {
+ if (config == NULL) {
+ return;
+ }
+
+ uint16_t minSdk = 0;
+ if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
+ || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
+ || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
+ minSdk = SDK_HONEYCOMB_MR2;
+ } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
+ != ResTable_config::UI_MODE_TYPE_ANY
+ || (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
+ != ResTable_config::UI_MODE_NIGHT_ANY) {
+ minSdk = SDK_FROYO;
+ } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
+ != ResTable_config::SCREENSIZE_ANY
+ || (config->screenLayout & ResTable_config::MASK_SCREENLONG)
+ != ResTable_config::SCREENLONG_ANY
+ || config->density != ResTable_config::DENSITY_DEFAULT) {
+ minSdk = SDK_DONUT;
+ }
+
+ if (minSdk > config->sdkVersion) {
+ config->sdkVersion = minSdk;
+ }
+}
+
+bool parseMcc(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->mcc = 0;
+ return true;
+ }
+ const char* c = name;
+ if (tolower(*c) != 'm') return false;
+ c++;
+ if (tolower(*c) != 'c') return false;
+ c++;
+ if (tolower(*c) != 'c') return false;
+ c++;
+
+ const char* val = c;
+
+ while (*c >= '0' && *c <= '9') {
+ c++;
+ }
+ if (*c != 0) return false;
+ if (c-val != 3) return false;
+
+ int d = atoi(val);
+ if (d != 0) {
+ if (out) out->mcc = d;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseMnc(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->mcc = 0;
+ return true;
+ }
+ const char* c = name;
+ if (tolower(*c) != 'm') return false;
+ c++;
+ if (tolower(*c) != 'n') return false;
+ c++;
+ if (tolower(*c) != 'c') return false;
+ c++;
+
+ const char* val = c;
+
+ while (*c >= '0' && *c <= '9') {
+ c++;
+ }
+ if (*c != 0) return false;
+ if (c-val == 0 || c-val > 3) return false;
+
+ if (out) {
+ out->mnc = atoi(val);
+ if (out->mnc == 0) {
+ out->mnc = ACONFIGURATION_MNC_ZERO;
+ }
+ }
+
+ return true;
+}
+
+bool parseLayoutDirection(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+ | ResTable_config::LAYOUTDIR_ANY;
+ return true;
+ } else if (strcmp(name, "ldltr") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+ | ResTable_config::LAYOUTDIR_LTR;
+ return true;
+ } else if (strcmp(name, "ldrtl") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+ | ResTable_config::LAYOUTDIR_RTL;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_ANY;
+ return true;
+ } else if (strcmp(name, "small") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_SMALL;
+ return true;
+ } else if (strcmp(name, "normal") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_NORMAL;
+ return true;
+ } else if (strcmp(name, "large") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_LARGE;
+ return true;
+ } else if (strcmp(name, "xlarge") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_XLARGE;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+ | ResTable_config::SCREENLONG_ANY;
+ return true;
+ } else if (strcmp(name, "long") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+ | ResTable_config::SCREENLONG_YES;
+ return true;
+ } else if (strcmp(name, "notlong") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+ | ResTable_config::SCREENLONG_NO;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseOrientation(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->orientation = out->ORIENTATION_ANY;
+ return true;
+ } else if (strcmp(name, "port") == 0) {
+ if (out) out->orientation = out->ORIENTATION_PORT;
+ return true;
+ } else if (strcmp(name, "land") == 0) {
+ if (out) out->orientation = out->ORIENTATION_LAND;
+ return true;
+ } else if (strcmp(name, "square") == 0) {
+ if (out) out->orientation = out->ORIENTATION_SQUARE;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseUiModeType(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_ANY;
+ return true;
+ } else if (strcmp(name, "desk") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_DESK;
+ return true;
+ } else if (strcmp(name, "car") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_CAR;
+ return true;
+ } else if (strcmp(name, "television") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_TELEVISION;
+ return true;
+ } else if (strcmp(name, "appliance") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_APPLIANCE;
+ return true;
+ } else if (strcmp(name, "watch") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_WATCH;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseUiModeNight(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+ | ResTable_config::UI_MODE_NIGHT_ANY;
+ return true;
+ } else if (strcmp(name, "night") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+ | ResTable_config::UI_MODE_NIGHT_YES;
+ return true;
+ } else if (strcmp(name, "notnight") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+ | ResTable_config::UI_MODE_NIGHT_NO;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseDensity(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->density = ResTable_config::DENSITY_DEFAULT;
+ return true;
+ }
+
+ if (strcmp(name, "nodpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_NONE;
+ return true;
+ }
+
+ if (strcmp(name, "ldpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_LOW;
+ return true;
+ }
+
+ if (strcmp(name, "mdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_MEDIUM;
+ return true;
+ }
+
+ if (strcmp(name, "tvdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_TV;
+ return true;
+ }
+
+ if (strcmp(name, "hdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_HIGH;
+ return true;
+ }
+
+ if (strcmp(name, "xhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XHIGH;
+ return true;
+ }
+
+ if (strcmp(name, "xxhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XXHIGH;
+ return true;
+ }
+
+ if (strcmp(name, "xxxhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
+ return true;
+ }
+
+ char* c = (char*)name;
+ while (*c >= '0' && *c <= '9') {
+ c++;
+ }
+
+ // check that we have 'dpi' after the last digit.
+ if (toupper(c[0]) != 'D' ||
+ toupper(c[1]) != 'P' ||
+ toupper(c[2]) != 'I' ||
+ c[3] != 0) {
+ return false;
+ }
+
+ // temporarily replace the first letter with \0 to
+ // use atoi.
+ char tmp = c[0];
+ c[0] = '\0';
+
+ int d = atoi(name);
+ c[0] = tmp;
+
+ if (d != 0) {
+ if (out) out->density = d;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseTouchscreen(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
+ return true;
+ } else if (strcmp(name, "notouch") == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
+ return true;
+ } else if (strcmp(name, "stylus") == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
+ return true;
+ } else if (strcmp(name, "finger") == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseKeysHidden(const char* name, ResTable_config* out) {
+ uint8_t mask = 0;
+ uint8_t value = 0;
+ if (strcmp(name, kWildcardName) == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_ANY;
+ } else if (strcmp(name, "keysexposed") == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_NO;
+ } else if (strcmp(name, "keyshidden") == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_YES;
+ } else if (strcmp(name, "keyssoft") == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_SOFT;
+ }
+
+ if (mask != 0) {
+ if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseKeyboard(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->keyboard = out->KEYBOARD_ANY;
+ return true;
+ } else if (strcmp(name, "nokeys") == 0) {
+ if (out) out->keyboard = out->KEYBOARD_NOKEYS;
+ return true;
+ } else if (strcmp(name, "qwerty") == 0) {
+ if (out) out->keyboard = out->KEYBOARD_QWERTY;
+ return true;
+ } else if (strcmp(name, "12key") == 0) {
+ if (out) out->keyboard = out->KEYBOARD_12KEY;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseNavHidden(const char* name, ResTable_config* out) {
+ uint8_t mask = 0;
+ uint8_t value = 0;
+ if (strcmp(name, kWildcardName) == 0) {
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_ANY;
+ } else if (strcmp(name, "navexposed") == 0) {
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_NO;
+ } else if (strcmp(name, "navhidden") == 0) {
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_YES;
+ }
+
+ if (mask != 0) {
+ if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseNavigation(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->navigation = out->NAVIGATION_ANY;
+ return true;
+ } else if (strcmp(name, "nonav") == 0) {
+ if (out) out->navigation = out->NAVIGATION_NONAV;
+ return true;
+ } else if (strcmp(name, "dpad") == 0) {
+ if (out) out->navigation = out->NAVIGATION_DPAD;
+ return true;
+ } else if (strcmp(name, "trackball") == 0) {
+ if (out) out->navigation = out->NAVIGATION_TRACKBALL;
+ return true;
+ } else if (strcmp(name, "wheel") == 0) {
+ if (out) out->navigation = out->NAVIGATION_WHEEL;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseScreenSize(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->screenWidth = out->SCREENWIDTH_ANY;
+ out->screenHeight = out->SCREENHEIGHT_ANY;
+ }
+ return true;
+ }
+
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || *x != 'x') return false;
+ String8 xName(name, x-name);
+ x++;
+
+ const char* y = x;
+ while (*y >= '0' && *y <= '9') y++;
+ if (y == name || *y != 0) return false;
+ String8 yName(x, y-x);
+
+ uint16_t w = (uint16_t)atoi(xName.string());
+ uint16_t h = (uint16_t)atoi(yName.string());
+ if (w < h) {
+ return false;
+ }
+
+ if (out) {
+ out->screenWidth = w;
+ out->screenHeight = h;
+ }
+
+ return true;
+}
+
+bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 's') return false;
+ name++;
+ if (*name != 'w') return false;
+ name++;
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+ String8 xName(name, x-name);
+
+ if (out) {
+ out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
+ }
+
+ return true;
+}
+
+bool parseScreenWidthDp(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->screenWidthDp = out->SCREENWIDTH_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 'w') return false;
+ name++;
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+ String8 xName(name, x-name);
+
+ if (out) {
+ out->screenWidthDp = (uint16_t)atoi(xName.string());
+ }
+
+ return true;
+}
+
+bool parseScreenHeightDp(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->screenHeightDp = out->SCREENWIDTH_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 'h') return false;
+ name++;
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+ String8 xName(name, x-name);
+
+ if (out) {
+ out->screenHeightDp = (uint16_t)atoi(xName.string());
+ }
+
+ return true;
+}
+
+bool parseVersion(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->sdkVersion = out->SDKVERSION_ANY;
+ out->minorVersion = out->MINORVERSION_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 'v') {
+ return false;
+ }
+
+ name++;
+ const char* s = name;
+ while (*s >= '0' && *s <= '9') s++;
+ if (s == name || *s != 0) return false;
+ String8 sdkName(name, s-name);
+
+ if (out) {
+ out->sdkVersion = (uint16_t)atoi(sdkName.string());
+ out->minorVersion = 0;
+ }
+
+ return true;
+}
+
+String8 getVersion(const ResTable_config& config) {
+ return String8::format("v%u", config.sdkVersion);
+}
+
+bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMask) {
+ return a.diff(b) == axisMask;
+}
+
+} // namespace AaptConfig
diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h
new file mode 100644
index 0000000..2963539
--- /dev/null
+++ b/tools/aapt/AaptConfig.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAPT_CONFIG_H
+#define __AAPT_CONFIG_H
+
+#include <set>
+#include <utils/String8.h>
+
+#include "ConfigDescription.h"
+
+/**
+ * Utility methods for dealing with configurations.
+ */
+namespace AaptConfig {
+
+/**
+ * Parse a string of the form 'fr-sw600dp-land' and fill in the
+ * given ResTable_config with resulting configuration parameters.
+ *
+ * The resulting configuration has the appropriate sdkVersion defined
+ * for backwards compatibility.
+ */
+bool parse(const android::String8& str, ConfigDescription* out = NULL);
+
+/**
+ * Parse a comma separated list of configuration strings. Duplicate configurations
+ * will be removed.
+ *
+ * Example input: "fr,de-land,fr-sw600dp-land"
+ */
+bool parseCommaSeparatedList(const android::String8& str, std::set<ConfigDescription>* outSet);
+
+/**
+ * If the configuration uses an axis that was added after
+ * the original Android release, make sure the SDK version
+ * is set accordingly.
+ */
+void applyVersionForCompatibility(ConfigDescription* config);
+
+// Individual axis
+bool parseMcc(const char* str, android::ResTable_config* out = NULL);
+bool parseMnc(const char* str, android::ResTable_config* out = NULL);
+bool parseLayoutDirection(const char* str, android::ResTable_config* out = NULL);
+bool parseSmallestScreenWidthDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenWidthDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenHeightDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenLayoutSize(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenLayoutLong(const char* str, android::ResTable_config* out = NULL);
+bool parseOrientation(const char* str, android::ResTable_config* out = NULL);
+bool parseUiModeType(const char* str, android::ResTable_config* out = NULL);
+bool parseUiModeNight(const char* str, android::ResTable_config* out = NULL);
+bool parseDensity(const char* str, android::ResTable_config* out = NULL);
+bool parseTouchscreen(const char* str, android::ResTable_config* out = NULL);
+bool parseKeysHidden(const char* str, android::ResTable_config* out = NULL);
+bool parseKeyboard(const char* str, android::ResTable_config* out = NULL);
+bool parseNavHidden(const char* str, android::ResTable_config* out = NULL);
+bool parseNavigation(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenSize(const char* str, android::ResTable_config* out = NULL);
+bool parseVersion(const char* str, android::ResTable_config* out = NULL);
+
+android::String8 getVersion(const android::ResTable_config& config);
+
+/**
+ * Returns true if the two configurations only differ by the specified axis.
+ * The axis mask is a bitmask of CONFIG_* constants.
+ */
+bool isSameExcept(const android::ResTable_config& a, const android::ResTable_config& b, int configMask);
+
+} // namespace AaptConfig
+
+#endif // __AAPT_CONFIG_H
diff --git a/tools/aapt/AaptUtil.cpp b/tools/aapt/AaptUtil.cpp
new file mode 100644
index 0000000..293e144
--- /dev/null
+++ b/tools/aapt/AaptUtil.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AaptUtil.h"
+
+using android::Vector;
+using android::String8;
+
+namespace AaptUtil {
+
+Vector<String8> split(const String8& str, const char sep) {
+ Vector<String8> parts;
+ const char* p = str.string();
+ const char* q;
+
+ while (true) {
+ q = strchr(p, sep);
+ if (q == NULL) {
+ parts.add(String8(p, strlen(p)));
+ return parts;
+ }
+
+ parts.add(String8(p, q-p));
+ p = q + 1;
+ }
+ return parts;
+}
+
+Vector<String8> splitAndLowerCase(const String8& str, const char sep) {
+ Vector<String8> parts;
+ const char* p = str.string();
+ const char* q;
+
+ while (true) {
+ q = strchr(p, sep);
+ if (q == NULL) {
+ String8 val(p, strlen(p));
+ val.toLower();
+ parts.add(val);
+ return parts;
+ }
+
+ String8 val(p, q-p);
+ val.toLower();
+ parts.add(val);
+ p = q + 1;
+ }
+ return parts;
+}
+
+} // namespace AaptUtil
diff --git a/tools/aapt/AaptUtil.h b/tools/aapt/AaptUtil.h
new file mode 100644
index 0000000..47a704a
--- /dev/null
+++ b/tools/aapt/AaptUtil.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAPT_UTIL_H
+#define __AAPT_UTIL_H
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace AaptUtil {
+
+android::Vector<android::String8> split(const android::String8& str, const char sep);
+android::Vector<android::String8> splitAndLowerCase(const android::String8& str, const char sep);
+
+} // namespace AaptUtil
+
+#endif // __AAPT_UTIL_H
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 806f8ff..700afa1 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -1,104 +1,168 @@
-#
-# Copyright 2006 The Android Open Source Project
#
-# Android Asset Packaging Tool
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# This tool is prebuilt if we're doing an app-only build.
ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
+# ==========================================================
+# Setup some common variables for the different build
+# targets here.
+# ==========================================================
+LOCAL_PATH:= $(call my-dir)
-aapt_src_files := \
- AaptAssets.cpp \
- Command.cpp \
- CrunchCache.cpp \
- FileFinder.cpp \
- Main.cpp \
- Package.cpp \
- StringPool.cpp \
- XMLNode.cpp \
- ResourceFilter.cpp \
- ResourceIdCache.cpp \
- ResourceTable.cpp \
- Images.cpp \
- Resource.cpp \
+aaptMain := Main.cpp
+aaptSources := \
+ AaptAssets.cpp \
+ AaptConfig.cpp \
+ AaptUtil.cpp \
+ ApkBuilder.cpp \
+ Command.cpp \
+ CrunchCache.cpp \
+ FileFinder.cpp \
+ Package.cpp \
+ StringPool.cpp \
+ XMLNode.cpp \
+ ResourceFilter.cpp \
+ ResourceIdCache.cpp \
+ ResourceTable.cpp \
+ Images.cpp \
+ Resource.cpp \
pseudolocalize.cpp \
SourcePos.cpp \
- WorkQueue.cpp \
+ WorkQueue.cpp \
ZipEntry.cpp \
ZipFile.cpp \
- qsort_r_compat.c
+ qsort_r_compat.c
+
+aaptTests := \
+ tests/AaptConfig_test.cpp \
+ tests/AaptGroupEntry_test.cpp \
+ tests/ResourceFilter_test.cpp
+
+aaptCIncludes := \
+ external/libpng \
+ external/zlib
+
+aaptHostLdLibs :=
+aaptHostStaticLibs := \
+ libandroidfw \
+ libpng \
+ liblog \
+ libutils \
+ libcutils \
+ libexpat \
+ libziparchive-host
-LOCAL_PATH:= $(call my-dir)
+ifeq ($(HOST_OS),linux)
+ aaptHostLdLibs += -lrt -ldl -lpthread
+endif
+
+# Statically link libz for MinGW (Win SDK under Linux),
+# and dynamically link for all others.
+ifneq ($(strip $(USE_MINGW)),)
+ aaptHostStaticLibs += libz
+else
+ aaptHostLdLibs += -lz
+endif
+
+
+# ==========================================================
+# Build the host static library: libaapt
+# ==========================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(aapt_src_files)
+LOCAL_MODULE := libaapt
+
+LOCAL_SRC_FILES := $(aaptSources)
+LOCAL_C_INCLUDES += $(aaptCIncludes)
LOCAL_CFLAGS += -Wno-format-y2k
+LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
ifeq (darwin,$(HOST_OS))
LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
endif
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
+include $(BUILD_HOST_STATIC_LIBRARY)
-LOCAL_C_INCLUDES += external/libpng
-LOCAL_C_INCLUDES += external/zlib
-LOCAL_STATIC_LIBRARIES := \
- libandroidfw \
- libutils \
- libcutils \
- libexpat \
- libpng \
- liblog \
- libziparchive-host
+# ==========================================================
+# Build the host executable: aapt
+# ==========================================================
+include $(CLEAR_VARS)
-ifeq ($(HOST_OS),linux)
-LOCAL_LDLIBS += -lrt -ldl -lpthread
-endif
+LOCAL_MODULE := aapt
-# Statically link libz for MinGW (Win SDK under Linux),
-# and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
- LOCAL_STATIC_LIBRARIES += libz
-else
- LOCAL_LDLIBS += -lz
-endif
+LOCAL_SRC_FILES := $(aaptMain)
-LOCAL_MODULE := aapt
+LOCAL_STATIC_LIBRARIES += \
+ libaapt \
+ $(aaptHostStaticLibs)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
include $(BUILD_HOST_EXECUTABLE)
-# aapt for running on the device
-# =========================================================
-ifneq ($(SDK_ONLY),true)
+
+# ==========================================================
+# Build the host tests: libaapt_tests
+# ==========================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(aapt_src_files)
+LOCAL_MODULE := libaapt_tests
-LOCAL_MODULE := aapt
+LOCAL_SRC_FILES += $(aaptTests)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)
-LOCAL_C_INCLUDES += bionic
-LOCAL_C_INCLUDES += bionic/libstdc++/include
-LOCAL_C_INCLUDES += external/stlport/stlport
-LOCAL_C_INCLUDES += external/libpng
-LOCAL_C_INCLUDES += external/zlib
+LOCAL_STATIC_LIBRARIES += \
+ libaapt \
+ $(aaptHostStaticLibs)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
-LOCAL_CFLAGS += -Wno-non-virtual-dtor
+include $(BUILD_HOST_NATIVE_TEST)
+
+
+# ==========================================================
+# Build the device executable: aapt
+# ==========================================================
+ifneq ($(SDK_ONLY),true)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := aapt
+
+LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
+LOCAL_C_INCLUDES += \
+ $(aaptCIncludes) \
+ bionic \
+ external/stlport/stlport
LOCAL_SHARED_LIBRARIES := \
- libandroidfw \
- libutils \
- libcutils \
- libpng \
- liblog \
- libz
+ libandroidfw \
+ libutils \
+ libcutils \
+ libpng \
+ liblog \
+ libz
LOCAL_STATIC_LIBRARIES := \
- libstlport_static \
- libexpat_static
+ libstlport_static \
+ libexpat_static
+
+LOCAL_CPPFLAGS += -Wno-non-virtual-dtor
include $(BUILD_EXECUTABLE)
-endif
+
+endif # Not SDK_ONLY
endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aapt/ApkBuilder.cpp b/tools/aapt/ApkBuilder.cpp
new file mode 100644
index 0000000..12f6040
--- /dev/null
+++ b/tools/aapt/ApkBuilder.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AaptAssets.h"
+#include "ApkBuilder.h"
+
+using namespace android;
+
+ApkBuilder::ApkBuilder(const sp<WeakResourceFilter>& configFilter)
+ : mConfigFilter(configFilter)
+ , mDefaultFilter(new AndResourceFilter()) {
+ // Add the default split, which is present for all APKs.
+ mDefaultFilter->addFilter(mConfigFilter);
+ mSplits.add(new ApkSplit(std::set<ConfigDescription>(), mDefaultFilter, true));
+}
+
+status_t ApkBuilder::createSplitForConfigs(const std::set<ConfigDescription>& configs) {
+ const size_t N = mSplits.size();
+ for (size_t i = 0; i < N; i++) {
+ const std::set<ConfigDescription>& splitConfigs = mSplits[i]->getConfigs();
+ std::set<ConfigDescription>::const_iterator iter = configs.begin();
+ for (; iter != configs.end(); iter++) {
+ if (splitConfigs.count(*iter) > 0) {
+ // Can't have overlapping configurations.
+ fprintf(stderr, "ERROR: Split configuration '%s' is already defined "
+ "in another split.\n", iter->toString().string());
+ return ALREADY_EXISTS;
+ }
+ }
+ }
+
+ sp<StrongResourceFilter> splitFilter = new StrongResourceFilter(configs);
+
+ // Add the inverse filter of this split filter to the base apk filter so it will
+ // omit resources that belong in this split.
+ mDefaultFilter->addFilter(new InverseResourceFilter(splitFilter));
+
+ // Now add the apk-wide config filter to our split filter.
+ sp<AndResourceFilter> filter = new AndResourceFilter();
+ filter->addFilter(splitFilter);
+ filter->addFilter(mConfigFilter);
+ mSplits.add(new ApkSplit(configs, filter));
+ return NO_ERROR;
+}
+
+status_t ApkBuilder::addEntry(const String8& path, const sp<AaptFile>& file) {
+ const size_t N = mSplits.size();
+ for (size_t i = 0; i < N; i++) {
+ if (mSplits[i]->matches(file)) {
+ return mSplits.editItemAt(i)->addEntry(path, file);
+ }
+ }
+ // Entry can be dropped if it doesn't match any split. This will only happen
+ // if the enry doesn't mConfigFilter.
+ return NO_ERROR;
+}
+
+void ApkBuilder::print() const {
+ fprintf(stderr, "APK Builder\n");
+ fprintf(stderr, "-----------\n");
+ const size_t N = mSplits.size();
+ for (size_t i = 0; i < N; i++) {
+ mSplits[i]->print();
+ fprintf(stderr, "\n");
+ }
+}
+
+ApkSplit::ApkSplit(const std::set<ConfigDescription>& configs, const sp<ResourceFilter>& filter, bool isBase)
+ : mConfigs(configs), mFilter(filter), mIsBase(isBase) {
+ std::set<ConfigDescription>::const_iterator iter = configs.begin();
+ for (; iter != configs.end(); iter++) {
+ if (mName.size() > 0) {
+ mName.append(",");
+ mDirName.append("_");
+ }
+
+ String8 configStr = iter->toString();
+ mName.append(configStr);
+ mDirName.append(configStr);
+ }
+}
+
+status_t ApkSplit::addEntry(const String8& path, const sp<AaptFile>& file) {
+ if (!mFiles.insert(OutputEntry(path, file)).second) {
+ // Duplicate file.
+ return ALREADY_EXISTS;
+ }
+ return NO_ERROR;
+}
+
+void ApkSplit::print() const {
+ fprintf(stderr, "APK Split '%s'\n", mName.string());
+
+ std::set<OutputEntry>::const_iterator iter = mFiles.begin();
+ for (; iter != mFiles.end(); iter++) {
+ fprintf(stderr, " %s (%s)\n", iter->getPath().string(), iter->getFile()->getSourceFile().string());
+ }
+}
diff --git a/tools/aapt/ApkBuilder.h b/tools/aapt/ApkBuilder.h
new file mode 100644
index 0000000..db23c84
--- /dev/null
+++ b/tools/aapt/ApkBuilder.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APK_BUILDER_H
+#define __APK_BUILDER_H
+
+#include <set>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include "ConfigDescription.h"
+#include "OutputSet.h"
+#include "ResourceFilter.h"
+
+class ApkSplit;
+class AaptFile;
+
+class ApkBuilder : public android::RefBase {
+public:
+ ApkBuilder(const sp<WeakResourceFilter>& configFilter);
+
+ /**
+ * Tells the builder to generate a separate APK for resources that
+ * match the configurations specified. Split APKs can not have
+ * overlapping resources.
+ *
+ * NOTE: All splits should be set up before any files are added.
+ */
+ android::status_t createSplitForConfigs(const std::set<ConfigDescription>& configs);
+
+ /**
+ * Adds a file to be written to the final APK. It's name must not collide
+ * with that of any files previously added. When a Split APK is being
+ * generated, duplicates can exist as long as they are in different splits
+ * (resources.arsc, AndroidManifest.xml).
+ */
+ android::status_t addEntry(const String8& path, const android::sp<AaptFile>& file);
+
+ android::Vector<sp<ApkSplit> >& getSplits() {
+ return mSplits;
+ }
+
+ android::sp<ApkSplit> getBaseSplit() {
+ return mSplits[0];
+ }
+
+ void print() const;
+
+private:
+ android::sp<ResourceFilter> mConfigFilter;
+ android::sp<AndResourceFilter> mDefaultFilter;
+ android::Vector<sp<ApkSplit> > mSplits;
+};
+
+class ApkSplit : public OutputSet {
+public:
+ android::status_t addEntry(const String8& path, const android::sp<AaptFile>& file);
+
+ const std::set<OutputEntry>& getEntries() const {
+ return mFiles;
+ }
+
+ const std::set<ConfigDescription>& getConfigs() const {
+ return mConfigs;
+ }
+
+ bool matches(const sp<AaptFile>& file) const {
+ return mFilter->match(file->getGroupEntry().toParams());
+ }
+
+ sp<ResourceFilter> getResourceFilter() const {
+ return mFilter;
+ }
+
+ const android::String8& getPrintableName() const {
+ return mName;
+ }
+
+ const android::String8& getDirectorySafeName() const {
+ return mDirName;
+ }
+
+ bool isBase() const {
+ return mIsBase;
+ }
+
+ void print() const;
+
+private:
+ friend class ApkBuilder;
+
+ ApkSplit(const std::set<ConfigDescription>& configs, const android::sp<ResourceFilter>& filter, bool isBase=false);
+
+ std::set<ConfigDescription> mConfigs;
+ const sp<ResourceFilter> mFilter;
+ const bool mIsBase;
+ String8 mName;
+ String8 mDirName;
+ std::set<OutputEntry> mFiles;
+};
+
+#endif // __APK_BUILDER_H
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 382cf5e..ceb52a0 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -60,7 +60,7 @@ public:
mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
mUpdate(false), mExtending(false),
mRequireLocalization(false), mPseudolocalize(NO_PSEUDOLOCALIZATION),
- mWantUTF16(false), mValues(false),
+ mWantUTF16(false), mValues(false), mIncludeMetaData(false),
mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
mAutoAddOverlay(false), mGenDependencies(false),
@@ -68,10 +68,12 @@ public:
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
- mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), mExtraPackages(NULL),
- mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL),
- mUseCrunchCache(false), mErrorOnFailedInsert(false), mOutputTextSymbols(NULL),
+ mVersionCode(NULL), mVersionName(NULL), mReplaceVersion(false), mCustomPackage(NULL),
+ mExtraPackages(NULL), mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false),
+ mProduct(NULL), mUseCrunchCache(false), mErrorOnFailedInsert(false),
+ mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
+ mBuildSharedLibrary(false),
mArgc(0), mArgv(NULL)
{}
~Bundle(void) {}
@@ -107,6 +109,8 @@ public:
void setWantUTF16(bool val) { mWantUTF16 = val; }
bool getValues(void) const { return mValues; }
void setValues(bool val) { mValues = val; }
+ bool getIncludeMetaData(void) const { return mIncludeMetaData; }
+ void setIncludeMetaData(bool val) { mIncludeMetaData = val; }
int getCompressionMethod(void) const { return mCompressionMethod; }
void setCompressionMethod(int val) { mCompressionMethod = val; }
bool getJunkPath(void) const { return mJunkPath; }
@@ -123,6 +127,8 @@ public:
void setGenDependencies(bool val) { mGenDependencies = val; }
bool getErrorOnFailedInsert() { return mErrorOnFailedInsert; }
void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; }
+ bool getErrorOnMissingConfigEntry() { return mErrorOnMissingConfigEntry; }
+ void setErrorOnMissingConfigEntry(bool val) { mErrorOnMissingConfigEntry = val; }
bool getUTF16StringsOption() {
return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO);
@@ -145,10 +151,12 @@ public:
void setPublicOutputFile(const char* file) { mPublicOutputFile = file; }
const char* getRClassDir() const { return mRClassDir; }
void setRClassDir(const char* dir) { mRClassDir = dir; }
- const char* getConfigurations() const { return mConfigurations.size() > 0 ? mConfigurations.string() : NULL; }
+ const android::String8& getConfigurations() const { return mConfigurations; }
void addConfigurations(const char* val) { if (mConfigurations.size() > 0) { mConfigurations.append(","); mConfigurations.append(val); } else { mConfigurations = val; } }
- const char* getPreferredConfigurations() const { return mPreferredConfigurations.size() > 0 ? mPreferredConfigurations.string() : NULL; }
- void addPreferredConfigurations(const char* val) { if (mPreferredConfigurations.size() > 0) { mPreferredConfigurations.append(","); mPreferredConfigurations.append(val); } else { mPreferredConfigurations = val; } }
+ const android::String8& getPreferredDensity() const { return mPreferredDensity; }
+ void setPreferredDensity(const char* val) { mPreferredDensity = val; }
+ void addSplitConfigurations(const char* val) { mPartialConfigurations.add(android::String8(val)); }
+ const android::Vector<android::String8>& getSplitConfigurations() const { return mPartialConfigurations; }
const char* getResourceIntermediatesDir() const { return mResourceIntermediatesDir; }
void setResourceIntermediatesDir(const char* dir) { mResourceIntermediatesDir = dir; }
const android::Vector<const char*>& getPackageIncludes() const { return mPackageIncludes; }
@@ -170,6 +178,8 @@ public:
void setVersionCode(const char* val) { mVersionCode = val; }
const char* getVersionName() const { return mVersionName; }
void setVersionName(const char* val) { mVersionName = val; }
+ bool getReplaceVersion() { return mReplaceVersion; }
+ void setReplaceVersion(bool val) { mReplaceVersion = val; }
const char* getCustomPackage() const { return mCustomPackage; }
void setCustomPackage(const char* val) { mCustomPackage = val; }
const char* getExtraPackages() const { return mExtraPackages; }
@@ -190,6 +200,8 @@ public:
void setSingleCrunchInputFile(const char* val) { mSingleCrunchInputFile = val; }
const char* getSingleCrunchOutputFile() const { return mSingleCrunchOutputFile; }
void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; }
+ bool getBuildSharedLibrary() const { return mBuildSharedLibrary; }
+ void setBuildSharedLibrary(bool val) { mBuildSharedLibrary = val; }
/*
* Set and get the file specification.
@@ -261,6 +273,7 @@ private:
short mPseudolocalize;
bool mWantUTF16;
bool mValues;
+ bool mIncludeMetaData;
int mCompressionMethod;
bool mJunkPath;
const char* mOutputAPKFile;
@@ -268,7 +281,6 @@ private:
const char* mInstrumentationPackageNameOverride;
bool mAutoAddOverlay;
bool mGenDependencies;
- const char* mAssetSourceDir;
const char* mCrunchedOutputDir;
const char* mProguardFile;
const char* mAndroidManifestFile;
@@ -276,7 +288,8 @@ private:
const char* mRClassDir;
const char* mResourceIntermediatesDir;
android::String8 mConfigurations;
- android::String8 mPreferredConfigurations;
+ android::String8 mPreferredDensity;
+ android::Vector<android::String8> mPartialConfigurations;
android::Vector<const char*> mPackageIncludes;
android::Vector<const char*> mJarFiles;
android::Vector<const char*> mNoCompressExtensions;
@@ -289,6 +302,7 @@ private:
const char* mMaxSdkVersion;
const char* mVersionCode;
const char* mVersionName;
+ bool mReplaceVersion;
const char* mCustomPackage;
const char* mExtraPackages;
const char* mMaxResVersion;
@@ -297,9 +311,11 @@ private:
const char* mProduct;
bool mUseCrunchCache;
bool mErrorOnFailedInsert;
+ bool mErrorOnMissingConfigEntry;
const char* mOutputTextSymbols;
const char* mSingleCrunchInputFile;
const char* mSingleCrunchOutputFile;
+ bool mBuildSharedLibrary;
/* file specification */
int mArgc;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 34292fe..4e0a9fe 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -3,6 +3,7 @@
//
// Android Asset Packaging Tool main entry point.
//
+#include "ApkBuilder.h"
#include "Main.h"
#include "Bundle.h"
#include "ResourceFilter.h"
@@ -25,8 +26,9 @@ using namespace android;
*/
int doVersion(Bundle* bundle)
{
- if (bundle->getFileSpecCount() != 0)
+ if (bundle->getFileSpecCount() != 0) {
printf("(ignoring extra arguments)\n");
+ }
printf("Android Asset Packaging Tool, v0.2\n");
return 0;
@@ -46,13 +48,14 @@ ZipFile* openReadOnly(const char* fileName)
zip = new ZipFile;
result = zip->open(fileName, ZipFile::kOpenReadOnly);
if (result != NO_ERROR) {
- if (result == NAME_NOT_FOUND)
+ if (result == NAME_NOT_FOUND) {
fprintf(stderr, "ERROR: '%s' not found\n", fileName);
- else if (result == PERMISSION_DENIED)
+ } else if (result == PERMISSION_DENIED) {
fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
- else
+ } else {
fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
fileName);
+ }
delete zip;
return NULL;
}
@@ -73,8 +76,9 @@ ZipFile* openReadWrite(const char* fileName, bool okayToCreate)
int flags;
flags = ZipFile::kOpenReadWrite;
- if (okayToCreate)
+ if (okayToCreate) {
flags |= ZipFile::kOpenCreate;
+ }
zip = new ZipFile;
result = zip->open(fileName, flags);
@@ -94,12 +98,13 @@ bail:
*/
const char* compressionName(int method)
{
- if (method == ZipEntry::kCompressStored)
+ if (method == ZipEntry::kCompressStored) {
return "Stored";
- else if (method == ZipEntry::kCompressDeflated)
+ } else if (method == ZipEntry::kCompressDeflated) {
return "Deflated";
- else
+ } else {
return "Unknown";
+ }
}
/*
@@ -107,10 +112,11 @@ const char* compressionName(int method)
*/
int calcPercent(long uncompressedLen, long compressedLen)
{
- if (!uncompressedLen)
+ if (!uncompressedLen) {
return 0;
- else
+ } else {
return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
+ }
}
/*
@@ -135,8 +141,9 @@ int doList(Bundle* bundle)
zipFileName = bundle->getFileSpecEntry(0);
zip = openReadOnly(zipFileName);
- if (zip == NULL)
+ if (zip == NULL) {
goto bail;
+ }
int count, i;
@@ -248,7 +255,9 @@ String8 getAttribute(const ResXMLTree& tree, const char* ns,
Res_value value;
if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
if (value.dataType != Res_value::TYPE_STRING) {
- if (outError != NULL) *outError = "attribute is not a string value";
+ if (outError != NULL) {
+ *outError = "attribute is not a string value";
+ }
return String8();
}
}
@@ -266,7 +275,9 @@ static String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* o
Res_value value;
if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
if (value.dataType != Res_value::TYPE_STRING) {
- if (outError != NULL) *outError = "attribute is not a string value";
+ if (outError != NULL) {
+ *outError = "attribute is not a string value";
+ }
return String8();
}
}
@@ -286,7 +297,9 @@ static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
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";
+ if (outError != NULL) {
+ *outError = "attribute is not an integer value";
+ }
return defValue;
}
}
@@ -307,7 +320,9 @@ static int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXM
}
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";
+ if (outError != NULL) {
+ *outError = "attribute is not an integer value";
+ }
return defValue;
}
}
@@ -330,7 +345,9 @@ static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree&
}
resTable->resolveReference(&value, 0);
if (value.dataType != Res_value::TYPE_STRING) {
- if (outError != NULL) *outError = "attribute is not a string value";
+ if (outError != NULL) {
+ *outError = "attribute is not a string value";
+ }
return String8();
}
}
@@ -340,6 +357,49 @@ static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree&
return str ? String8(str, len) : String8();
}
+static void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable,
+ const ResXMLTree& tree, uint32_t attrRes, String8* outError)
+{
+ ssize_t idx = indexOfAttribute(tree, attrRes);
+ if (idx < 0) {
+ if (outError != NULL) {
+ *outError = "attribute could not be found";
+ }
+ return;
+ }
+ if (tree.getAttributeValue(idx, value) != NO_ERROR) {
+ if (value->dataType == Res_value::TYPE_REFERENCE) {
+ resTable->resolveReference(value, 0);
+ }
+ // The attribute was found and was resolved if need be.
+ return;
+ }
+ if (outError != NULL) {
+ *outError = "error getting resolved resource attribute";
+ }
+}
+
+static void printResolvedResourceAttribute(const ResTable* resTable, const ResXMLTree& tree,
+ uint32_t attrRes, String8 attrLabel, String8* outError)
+{
+ Res_value value;
+ getResolvedResourceAttribute(&value, resTable, tree, attrRes, outError);
+ if (*outError != "") {
+ *outError = "error print resolved resource attribute";
+ return;
+ }
+ if (value.dataType == Res_value::TYPE_STRING) {
+ String8 result = getResolvedAttribute(resTable, tree, attrRes, outError);
+ printf("%s='%s'", attrLabel.string(),
+ ResTable::normalizeForOutput(result.string()).string());
+ } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
+ value.dataType <= Res_value::TYPE_LAST_INT) {
+ printf("%s='%d'", attrLabel.string(), value.data);
+ } else {
+ printf("%s='0x%x'", attrLabel.string(), (int)value.data);
+ }
+}
+
// These are attribute resource constants for the platform, as found
// in android.R.attr
enum {
@@ -349,6 +409,7 @@ enum {
PERMISSION_ATTR = 0x01010006,
RESOURCE_ATTR = 0x01010025,
DEBUGGABLE_ATTR = 0x0101000f,
+ VALUE_ATTR = 0x01010024,
VERSION_CODE_ATTR = 0x0101021b,
VERSION_NAME_ATTR = 0x0101021c,
SCREEN_ORIENTATION_ATTR = 0x0101001e,
@@ -378,7 +439,7 @@ enum {
BANNER_ATTR = 0x10103f2,
};
-const char *getComponentName(String8 &pkgName, String8 &componentName) {
+String8 getComponentName(String8 &pkgName, String8 &componentName) {
ssize_t idx = componentName.find(".");
String8 retStr(pkgName);
if (idx == 0) {
@@ -387,12 +448,12 @@ const char *getComponentName(String8 &pkgName, String8 &componentName) {
retStr += ".";
retStr += componentName;
} else {
- return componentName.string();
+ return componentName;
}
- return retStr.string();
+ return retStr;
}
-static void printCompatibleScreens(ResXMLTree& tree) {
+static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
size_t len;
ResXMLTree::event_code_t code;
int depth = 0;
@@ -410,7 +471,12 @@ static void printCompatibleScreens(ResXMLTree& tree) {
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return;
+ }
+ String8 tag(ctag16);
if (tag == "screen") {
int32_t screenSize = getIntegerAttribute(tree,
SCREEN_SIZE_ATTR, NULL, -1);
@@ -428,6 +494,29 @@ static void printCompatibleScreens(ResXMLTree& tree) {
printf("\n");
}
+static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
+ printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
+ if (maxSdkVersion != -1) {
+ printf(" maxSdkVersion='%d'", maxSdkVersion);
+ }
+ printf("\n");
+
+ if (optional) {
+ printf("optional-permission: name='%s'",
+ ResTable::normalizeForOutput(name.string()).string());
+ if (maxSdkVersion != -1) {
+ printf(" maxSdkVersion='%d'", maxSdkVersion);
+ }
+ printf("\n");
+ }
+}
+
+static void printUsesImpliedPermission(const String8& name, const String8& reason) {
+ printf("uses-implied-permission: name='%s' reason='%s'\n",
+ ResTable::normalizeForOutput(name.string()).string(),
+ ResTable::normalizeForOutput(reason.string()).string());
+}
+
Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
String8 *outError = NULL)
{
@@ -452,7 +541,12 @@ Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return Vector<String8>();
+ }
+ String8 tag(ctag16);
if (depth == 0 && tag == serviceTagName) {
withinApduService = false;
@@ -460,7 +554,12 @@ Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool
} else if (code == ResXMLTree::START_TAG) {
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return Vector<String8>();
+ }
+ String8 tag(ctag16);
if (depth == 1) {
if (tag == serviceTagName) {
@@ -627,7 +726,12 @@ int doDump(Bundle* bundle)
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ goto bail;
+ }
+ String8 tag(ctag16);
//printf("Depth %d tag %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
@@ -635,7 +739,7 @@ int doDump(Bundle* bundle)
goto bail;
}
String8 pkg = getAttribute(tree, NULL, "package", NULL);
- printf("package: %s\n", pkg.string());
+ printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
} else if (depth == 2 && tag == "permission") {
String8 error;
String8 name = getAttribute(tree, NAME_ATTR, &error);
@@ -643,7 +747,8 @@ int doDump(Bundle* bundle)
fprintf(stderr, "ERROR: %s\n", error.string());
goto bail;
}
- printf("permission: %s\n", name.string());
+ printf("permission: %s\n",
+ ResTable::normalizeForOutput(name.string()).string());
} else if (depth == 2 && tag == "uses-permission") {
String8 error;
String8 name = getAttribute(tree, NAME_ATTR, &error);
@@ -651,11 +756,9 @@ int doDump(Bundle* bundle)
fprintf(stderr, "ERROR: %s\n", error.string());
goto bail;
}
- printf("uses-permission: %s\n", name.string());
- int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
- if (!req) {
- printf("optional-permission: %s\n", name.string());
- }
+ printUsesPermission(name,
+ getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
+ getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
}
}
} else if (strcmp("badging", option) == 0) {
@@ -668,7 +771,9 @@ int doDump(Bundle* bundle)
const size_t NC = configs.size();
for (size_t i=0; i<NC; i++) {
int dens = configs[i].density;
- if (dens == 0) dens = 160;
+ if (dens == 0) {
+ dens = 160;
+ }
densities.add(dens);
}
@@ -802,7 +907,8 @@ int doDump(Bundle* bundle)
printf("supports-input: '");
const size_t N = supportedInput.size();
for (size_t i=0; i<N; i++) {
- printf("%s", supportedInput[i].string());
+ printf("%s", ResTable::normalizeForOutput(
+ supportedInput[i].string()).string());
if (i != N - 1) {
printf("' '");
} else {
@@ -815,25 +921,27 @@ int doDump(Bundle* bundle)
withinSupportsInput = false;
} else if (depth < 3) {
if (withinActivity && isMainActivity) {
- const char *aName = getComponentName(pkg, activityName);
+ String8 aName(getComponentName(pkg, activityName));
if (isLauncherActivity) {
printf("launchable-activity:");
- if (aName != NULL) {
- printf(" name='%s' ", aName);
+ if (aName.length() > 0) {
+ printf(" name='%s' ",
+ ResTable::normalizeForOutput(aName.string()).string());
}
printf(" label='%s' icon='%s'\n",
- activityLabel.string(),
- activityIcon.string());
+ ResTable::normalizeForOutput(activityLabel.string()).string(),
+ ResTable::normalizeForOutput(activityIcon.string()).string());
}
if (isLeanbackLauncherActivity) {
printf("leanback-launchable-activity:");
- if (aName != NULL) {
- printf(" name='%s' ", aName);
+ if (aName.length() > 0) {
+ printf(" name='%s' ",
+ ResTable::normalizeForOutput(aName.string()).string());
}
printf(" label='%s' icon='%s' banner='%s'\n",
- activityLabel.string(),
- activityIcon.string(),
- activityBanner.string());
+ ResTable::normalizeForOutput(activityLabel.string()).string(),
+ ResTable::normalizeForOutput(activityIcon.string()).string(),
+ ResTable::normalizeForOutput(activityBanner.string()).string());
}
}
if (!hasIntentFilter) {
@@ -882,7 +990,13 @@ int doDump(Bundle* bundle)
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ goto bail;
+ }
+ String8 tag(ctag16);
//printf("Depth %d, %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
@@ -890,7 +1004,8 @@ int doDump(Bundle* bundle)
goto bail;
}
pkg = getAttribute(tree, NULL, "package", NULL);
- printf("package: name='%s' ", pkg.string());
+ printf("package: name='%s' ",
+ ResTable::normalizeForOutput(pkg.string()).string());
int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
if (error != "") {
fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
@@ -906,7 +1021,8 @@ int doDump(Bundle* bundle)
fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
goto bail;
}
- printf("versionName='%s'\n", versionName.string());
+ printf("versionName='%s'\n",
+ ResTable::normalizeForOutput(versionName.string()).string());
} else if (depth == 2) {
withinApplication = false;
if (tag == "application") {
@@ -921,13 +1037,14 @@ int doDump(Bundle* bundle)
if (llabel != "") {
if (localeStr == NULL || strlen(localeStr) == 0) {
label = llabel;
- printf("application-label:'%s'\n", llabel.string());
+ printf("application-label:'%s'\n",
+ ResTable::normalizeForOutput(llabel.string()).string());
} else {
if (label == "") {
label = llabel;
}
printf("application-label-%s:'%s'\n", localeStr,
- llabel.string());
+ ResTable::normalizeForOutput(llabel.string()).string());
}
}
}
@@ -939,7 +1056,8 @@ int doDump(Bundle* bundle)
assets.setConfiguration(tmpConfig);
String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
if (icon != "") {
- printf("application-icon-%d:'%s'\n", densities[i], icon.string());
+ printf("application-icon-%d:'%s'\n", densities[i],
+ ResTable::normalizeForOutput(icon.string()).string());
}
}
assets.setConfiguration(config);
@@ -954,8 +1072,9 @@ int doDump(Bundle* bundle)
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());
+ printf("application: label='%s' ",
+ ResTable::normalizeForOutput(label.string()).string());
+ printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
if (testOnly != 0) {
printf("testOnly='%d'\n", testOnly);
}
@@ -979,7 +1098,8 @@ int doDump(Bundle* bundle)
goto bail;
}
if (name == "Donut") targetSdk = 4;
- printf("sdkVersion:'%s'\n", name.string());
+ printf("sdkVersion:'%s'\n",
+ ResTable::normalizeForOutput(name.string()).string());
} else if (code != -1) {
targetSdk = code;
printf("sdkVersion:'%d'\n", code);
@@ -998,7 +1118,8 @@ int doDump(Bundle* bundle)
goto bail;
}
if (name == "Donut" && targetSdk < 4) targetSdk = 4;
- printf("targetSdkVersion:'%s'\n", name.string());
+ printf("targetSdkVersion:'%s'\n",
+ ResTable::normalizeForOutput(name.string()).string());
} else if (code != -1) {
if (targetSdk < code) {
targetSdk = code;
@@ -1103,7 +1224,8 @@ int doDump(Bundle* bundle)
specScreenLandscapeFeature = true;
}
printf("uses-feature%s:'%s'\n",
- req ? "" : "-not-required", name.string());
+ req ? "" : "-not-required",
+ ResTable::normalizeForOutput(name.string()).string());
} else {
int vers = getIntegerAttribute(tree,
GL_ES_VERSION_ATTR, &error);
@@ -1161,12 +1283,11 @@ int doDump(Bundle* bundle)
} else if (name == "android.permission.WRITE_CALL_LOG") {
hasWriteCallLogPermission = true;
}
- printf("uses-permission:'%s'\n", name.string());
- int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
- if (!req) {
- printf("optional-permission:'%s'\n", name.string());
- }
- } else {
+
+ printUsesPermission(name,
+ getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
+ getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
+ } else {
fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
error.string());
goto bail;
@@ -1174,7 +1295,8 @@ int doDump(Bundle* bundle)
} else if (tag == "uses-package") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
- printf("uses-package:'%s'\n", name.string());
+ printf("uses-package:'%s'\n",
+ ResTable::normalizeForOutput(name.string()).string());
} else {
fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
error.string());
@@ -1183,7 +1305,8 @@ int doDump(Bundle* bundle)
} else if (tag == "original-package") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
- printf("original-package:'%s'\n", name.string());
+ printf("original-package:'%s'\n",
+ ResTable::normalizeForOutput(name.string()).string());
} else {
fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
error.string());
@@ -1192,14 +1315,20 @@ int doDump(Bundle* bundle)
} else if (tag == "supports-gl-texture") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
- printf("supports-gl-texture:'%s'\n", name.string());
+ printf("supports-gl-texture:'%s'\n",
+ ResTable::normalizeForOutput(name.string()).string());
} else {
fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
error.string());
goto bail;
}
} else if (tag == "compatible-screens") {
- printCompatibleScreens(tree);
+ printCompatibleScreens(tree, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting compatible screens: %s\n",
+ error.string());
+ goto bail;
+ }
depth--;
} else if (tag == "package-verifier") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
@@ -1207,7 +1336,8 @@ int doDump(Bundle* bundle)
String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
if (publicKey != "" && error == "") {
printf("package-verifier: name='%s' publicKey='%s'\n",
- name.string(), publicKey.string());
+ ResTable::normalizeForOutput(name.string()).string(),
+ ResTable::normalizeForOutput(publicKey.string()).string());
}
}
}
@@ -1276,7 +1406,8 @@ int doDump(Bundle* bundle)
int req = getIntegerAttribute(tree,
REQUIRED_ATTR, NULL, 1);
printf("uses-library%s:'%s'\n",
- req ? "" : "-not-required", libraryName.string());
+ req ? "" : "-not-required", ResTable::normalizeForOutput(
+ libraryName.string()).string());
} else if (tag == "receiver") {
withinReceiver = true;
receiverName = getAttribute(tree, NAME_ATTR, &error);
@@ -1302,8 +1433,8 @@ int doDump(Bundle* bundle)
serviceName = getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for"
- " service: %s\n", error.string());
+ fprintf(stderr, "ERROR getting 'android:name' attribute for "
+ "service:%s\n", error.string());
goto bail;
}
@@ -1322,15 +1453,39 @@ int doDump(Bundle* bundle)
fprintf(stderr, "ERROR getting 'android:permission' attribute for"
" service '%s': %s\n", serviceName.string(), error.string());
}
- }
- } else if (withinSupportsInput && tag == "input-type") {
- String8 name = getAttribute(tree, NAME_ATTR, &error);
- if (name != "" && error == "") {
- supportedInput.add(name);
- } else {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
- error.string());
- goto bail;
+ } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
+ String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute for "
+ "meta-data:%s\n", error.string());
+ goto bail;
+ }
+ printf("meta-data: name='%s' ",
+ ResTable::normalizeForOutput(metaDataName.string()).string());
+ printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"),
+ &error);
+ if (error != "") {
+ // Try looking for a RESOURCE_ATTR
+ error = "";
+ printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR,
+ String8("resource"), &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:value' or "
+ "'android:resource' attribute for "
+ "meta-data:%s\n", error.string());
+ goto bail;
+ }
+ }
+ printf("\n");
+ } else if (withinSupportsInput && tag == "input-type") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+ if (name != "" && error == "") {
+ supportedInput.add(name);
+ } else {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
}
}
} else if (depth == 4) {
@@ -1387,14 +1542,16 @@ int doDump(Bundle* bundle)
}
}
}
- } else if ((depth == 5) && withinIntentFilter){
+ } else if ((depth == 5) && withinIntentFilter) {
String8 action;
if (tag == "action") {
action = getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ error.string());
goto bail;
}
+
if (withinActivity) {
if (action == "android.intent.action.MAIN") {
isMainActivity = true;
@@ -1429,7 +1586,8 @@ int doDump(Bundle* bundle)
if (tag == "category") {
String8 category = getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
+ fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
+ error.string());
goto bail;
}
if (withinActivity) {
@@ -1446,15 +1604,15 @@ int doDump(Bundle* bundle)
// Pre-1.6 implicitly granted permission compatibility logic
if (targetSdk < 4) {
if (!hasWriteExternalStoragePermission) {
- printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
- printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \
- "'targetSdkVersion < 4'\n");
+ printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
+ printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
+ String8("targetSdkVersion < 4"));
hasWriteExternalStoragePermission = true;
}
if (!hasReadPhoneStatePermission) {
- printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
- printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \
- "'targetSdkVersion < 4'\n");
+ printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
+ printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
+ String8("targetSdkVersion < 4"));
}
}
@@ -1463,22 +1621,22 @@ int doDump(Bundle* bundle)
// do this (regardless of target API version) because we can't have
// an app with write permission but not read permission.
if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
- printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
- printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \
- "'requested WRITE_EXTERNAL_STORAGE'\n");
+ printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
+ printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
+ String8("requested WRITE_EXTERNAL_STORAGE"));
}
// Pre-JellyBean call log permission compatibility.
if (targetSdk < 16) {
if (!hasReadCallLogPermission && hasReadContactsPermission) {
- printf("uses-permission:'android.permission.READ_CALL_LOG'\n");
- printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \
- "'targetSdkVersion < 16 and requested READ_CONTACTS'\n");
+ printUsesPermission(String8("android.permission.READ_CALL_LOG"));
+ printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
+ String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
}
if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
- printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n");
- printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \
- "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n");
+ printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
+ printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
+ String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
}
}
@@ -1503,7 +1661,7 @@ int doDump(Bundle* bundle)
printf("uses-implied-feature:'android.hardware.camera'," \
"'requested android.hardware.camera.autofocus feature'\n");
} else if (hasCameraPermission) {
- // if app wants to use camera but didn't request the feature, we infer
+ // if app wants to use camera but didn't request the feature, we infer
// that it meant to, and further that it wants autofocus
// (which was the 1.0 - 1.5 behavior)
printf("uses-feature:'android.hardware.camera'\n");
@@ -1656,7 +1814,9 @@ int doDump(Bundle* bundle)
if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
&& requiresSmallestWidthDp > 0) {
int compatWidth = compatibleWidthLimitDp;
- if (compatWidth <= 0) compatWidth = requiresSmallestWidthDp;
+ if (compatWidth <= 0) {
+ compatWidth = requiresSmallestWidthDp;
+ }
if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
smallScreen = -1;
} else {
@@ -1701,10 +1861,18 @@ int doDump(Bundle* bundle)
|| compatibleWidthLimitDp > 0) ? -1 : 0;
}
printf("supports-screens:");
- if (smallScreen != 0) printf(" 'small'");
- if (normalScreen != 0) printf(" 'normal'");
- if (largeScreen != 0) printf(" 'large'");
- if (xlargeScreen != 0) printf(" 'xlarge'");
+ if (smallScreen != 0) {
+ printf(" 'small'");
+ }
+ if (normalScreen != 0) {
+ printf(" 'normal'");
+ }
+ if (largeScreen != 0) {
+ printf(" 'large'");
+ }
+ if (xlargeScreen != 0) {
+ printf(" 'xlarge'");
+ }
printf("\n");
printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
if (requiresSmallestWidthDp > 0) {
@@ -1740,7 +1908,8 @@ int doDump(Bundle* bundle)
if (dir->getFileCount() > 0) {
printf("native-code:");
for (size_t i=0; i<dir->getFileCount(); i++) {
- printf(" '%s'", dir->getFileName(i).string());
+ printf(" '%s'", ResTable::normalizeForOutput(
+ dir->getFileName(i).string()).string());
}
printf("\n");
}
@@ -1813,7 +1982,8 @@ int doAdd(Bundle* bundle)
} else {
if (bundle->getJunkPath()) {
String8 storageName = String8(fileName).getPathLeaf();
- printf(" '%s' as '%s'...\n", fileName, storageName.string());
+ printf(" '%s' as '%s'...\n", fileName,
+ ResTable::normalizeForOutput(storageName.string()).string());
result = zip->add(fileName, storageName.string(),
bundle->getCompressionMethod(), NULL);
} else {
@@ -1823,12 +1993,13 @@ int doAdd(Bundle* bundle)
}
if (result != NO_ERROR) {
fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
- if (result == NAME_NOT_FOUND)
+ if (result == NAME_NOT_FOUND) {
fprintf(stderr, ": file not found\n");
- else if (result == ALREADY_EXISTS)
+ } else if (result == ALREADY_EXISTS) {
fprintf(stderr, ": already exists in archive\n");
- else
+ } else {
fprintf(stderr, "\n");
+ }
goto bail;
}
}
@@ -1895,6 +2066,58 @@ bail:
return (result != NO_ERROR);
}
+static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
+ const size_t numDirs = dir->getDirs().size();
+ for (size_t i = 0; i < numDirs; i++) {
+ bool ignore = ignoreConfig;
+ const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
+ const char* dirStr = subDir->getLeaf().string();
+ if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
+ ignore = true;
+ }
+ status_t err = addResourcesToBuilder(subDir, builder, ignore);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+
+ const size_t numFiles = dir->getFiles().size();
+ for (size_t i = 0; i < numFiles; i++) {
+ sp<AaptGroup> gp = dir->getFiles().valueAt(i);
+ const size_t numConfigs = gp->getFiles().size();
+ for (size_t j = 0; j < numConfigs; j++) {
+ status_t err = NO_ERROR;
+ if (ignoreConfig) {
+ err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
+ } else {
+ err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
+ }
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed to add %s (%s) to builder.\n",
+ gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
+ return err;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
+ if (split->isBase()) {
+ return original;
+ }
+
+ String8 ext(original.getPathExtension());
+ if (ext == String8(".apk")) {
+ return String8::format("%s_%s%s",
+ original.getBasePath().string(),
+ split->getDirectorySafeName().string(),
+ ext.string());
+ }
+
+ return String8::format("%s_%s", original.string(),
+ split->getDirectorySafeName().string());
+}
/*
* Package up an asset directory and associated application files.
@@ -1908,17 +2131,18 @@ int doPackage(Bundle* bundle)
int N;
FILE* fp;
String8 dependencyFile;
+ sp<ApkBuilder> builder;
// -c en_XA or/and ar_XB means do pseudolocalization
- ResourceFilter filter;
- err = filter.parse(bundle->getConfigurations());
+ sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
+ err = configFilter->parse(bundle->getConfigurations());
if (err != NO_ERROR) {
goto bail;
}
- if (filter.containsPseudo()) {
+ if (configFilter->containsPseudo()) {
bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
}
- if (filter.containsPseudoBidi()) {
+ if (configFilter->containsPseudoBidi()) {
bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
}
@@ -1966,9 +2190,32 @@ int doPackage(Bundle* bundle)
assets->print(String8());
}
+ // Create the ApkBuilder, which will collect the compiled files
+ // to write to the final APK (or sets of APKs if we are building
+ // a Split APK.
+ builder = new ApkBuilder(configFilter);
+
+ // If we are generating a Split APK, find out which configurations to split on.
+ if (bundle->getSplitConfigurations().size() > 0) {
+ const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
+ const size_t numSplits = splitStrs.size();
+ for (size_t i = 0; i < numSplits; i++) {
+ std::set<ConfigDescription> configs;
+ if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
+ fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
+ goto bail;
+ }
+
+ err = builder->createSplitForConfigs(configs);
+ if (err != NO_ERROR) {
+ goto bail;
+ }
+ }
+ }
+
// If they asked for any fileAs that need to be compiled, do so.
if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
- err = buildResources(bundle, assets);
+ err = buildResources(bundle, assets, builder);
if (err != 0) {
goto bail;
}
@@ -2055,11 +2302,24 @@ int doPackage(Bundle* bundle)
// Write the apk
if (outputAPKFile) {
- err = writeAPK(bundle, assets, String8(outputAPKFile));
+ // Gather all resources and add them to the APK Builder. The builder will then
+ // figure out which Split they belong in.
+ err = addResourcesToBuilder(assets, builder);
if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile);
goto bail;
}
+
+ const Vector<sp<ApkSplit> >& splits = builder->getSplits();
+ const size_t numSplits = splits.size();
+ for (size_t i = 0; i < numSplits; i++) {
+ const sp<ApkSplit>& split = splits[i];
+ String8 outputPath = buildApkName(String8(outputAPKFile), split);
+ err = writeAPK(bundle, outputPath, split);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
+ goto bail;
+ }
+ }
}
// If we've been asked to generate a dependency file, we need to finish up here.
@@ -2096,7 +2356,7 @@ bail:
*
* POSTCONDITIONS
* Destination directory will be updated to match the PNG files in
- * the source directory.
+ * the source directory.
*/
int doCrunch(Bundle* bundle)
{
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
new file mode 100644
index 0000000..779c423
--- /dev/null
+++ b/tools/aapt/ConfigDescription.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONFIG_DESCRIPTION_H
+#define __CONFIG_DESCRIPTION_H
+
+#include <androidfw/ResourceTypes.h>
+
+/**
+ * Subclass of ResTable_config that adds convenient
+ * initialization and comparison methods.
+ */
+struct ConfigDescription : public android::ResTable_config {
+ ConfigDescription() {
+ memset(this, 0, sizeof(*this));
+ size = sizeof(android::ResTable_config);
+ }
+ ConfigDescription(const android::ResTable_config&o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ size = sizeof(android::ResTable_config);
+ }
+ ConfigDescription(const ConfigDescription&o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ }
+
+ ConfigDescription& operator=(const android::ResTable_config& o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ size = sizeof(android::ResTable_config);
+ return *this;
+ }
+ ConfigDescription& operator=(const ConfigDescription& o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ return *this;
+ }
+
+ inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
+ inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
+ inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
+ inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
+ inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
+ inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
+};
+
+#endif // __CONFIG_DESCRIPTION_H
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index db74831..12f5b92 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -81,6 +81,12 @@ struct image_info
png_bytepp allocRows;
};
+static void log_warning(png_structp png_ptr, png_const_charp warning_message)
+{
+ const char* imageName = (const char*) png_get_error_ptr(png_ptr);
+ fprintf(stderr, "%s: libpng warning: %s\n", imageName, warning_message);
+}
+
static void read_png(const char* imageName,
png_structp read_ptr, png_infop read_info,
image_info* outImageInfo)
@@ -89,6 +95,8 @@ static void read_png(const char* imageName,
int bit_depth, interlace_type, compression_type;
int i;
+ png_set_error_fn(read_ptr, const_cast<char*>(imageName),
+ NULL /* use default errorfn */, log_warning);
png_read_info(read_ptr, read_info);
png_get_IHDR(read_ptr, read_info, &outImageInfo->width,
@@ -119,6 +127,8 @@ static void read_png(const char* imageName,
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(read_ptr);
+ png_set_interlace_handling(read_ptr);
+
png_read_update_info(read_ptr, read_info);
outImageInfo->rows = (png_bytepp)malloc(
@@ -931,7 +941,7 @@ static void analyze_image(const char *imageName, image_info &imageInfo, int gray
gg = *row++;
bb = *row++;
aa = *row++;
-
+
if (isGrayscale) {
*out++ = rr;
} else {
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index d1d3deb..5a60014 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -47,7 +47,7 @@ void usage(void)
" %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
" List contents of Zip-compatible archive.\n\n", gProgName);
fprintf(stderr,
- " %s d[ump] [--values] WHAT file.{apk} [asset [asset ...]]\n"
+ " %s d[ump] [--values] [--include-meta-data] WHAT file.{apk} [asset [asset ...]]\n"
" strings Print the contents of the resource table string pool in the APK.\n"
" badging Print the label and icon for the app declared in APK.\n"
" permissions Print the permissions from the APK.\n"
@@ -70,6 +70,7 @@ void usage(void)
" [-F apk-file] [-J R-file-dir] \\\n"
" [--product product1,product2,...] \\\n"
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
+ " [--split CONFIGS [--split CONFIGS]] \\\n"
" [raw-files-dir [raw-files-dir] ...] \\\n"
" [--output-text-symbols DIR]\n"
"\n"
@@ -138,6 +139,8 @@ void usage(void)
" --debug-mode\n"
" inserts android:debuggable=\"true\" in to the application node of the\n"
" manifest, making the application debuggable even on production devices.\n"
+ " --include-meta-data\n"
+ " when used with \"dump badging\" also includes meta-data tags.\n"
" --min-sdk-version\n"
" inserts android:minSdkVersion in to manifest. If the version is 7 or\n"
" higher, the default encoding for resources will be in UTF-8.\n"
@@ -151,6 +154,11 @@ void usage(void)
" inserts android:versionCode in to manifest.\n"
" --version-name\n"
" inserts android:versionName in to manifest.\n"
+ " --replace-version\n"
+ " If --version-code and/or --version-name are specified, these\n"
+ " values will replace any value already in the manifest. By\n"
+ " default, nothing is changed if the manifest already defines\n"
+ " these attributes.\n"
" --custom-package\n"
" generates R.java into a different package.\n"
" --extra-packages\n"
@@ -159,10 +167,12 @@ void usage(void)
" generate dependency files in the same directories for R.java and resource package\n"
" --auto-add-overlay\n"
" Automatically add resources that are only in overlays.\n"
- " --preferred-configurations\n"
- " Like the -c option for filtering out unneeded configurations, but\n"
- " only expresses a preference. If there is no resource available with\n"
- " the preferred configuration then it will not be stripped.\n"
+ " --preferred-density\n"
+ " Specifies a preference for a particular density. Resources that do not\n"
+ " match this density and have variants that are a closer match are removed.\n"
+ " --split\n"
+ " Builds a separate split APK for the configurations listed. This can\n"
+ " be loaded alongside the base APK at runtime.\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"
@@ -183,11 +193,16 @@ void usage(void)
" Make the resources ID non constant. This is required to make an R java class\n"
" that does not contain the final value but is used to make reusable compiled\n"
" libraries that need to access resources.\n"
+ " --shared-lib\n"
+ " Make a shared library resource package that can be loaded by an application\n"
+ " at runtime to access the libraries resources. Implies --non-constant-id.\n"
" --error-on-failed-insert\n"
" Forces aapt to return an error if it fails to insert values into the manifest\n"
" with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n"
" and --version-name.\n"
" Insertion typically fails if the manifest already defines the attribute.\n"
+ " --error-on-missing-config-entry\n"
+ " Forces aapt to return an error if it fails to find an entry for a configuration.\n"
" --output-text-symbols\n"
" Generates a text file containing the resource symbols of the R class in the\n"
" specified folder.\n"
@@ -528,8 +543,12 @@ int main(int argc, char* const argv[])
goto bail;
}
bundle.setVersionName(argv[0]);
+ } else if (strcmp(cp, "-replace-version") == 0) {
+ bundle.setReplaceVersion(true);
} else if (strcmp(cp, "-values") == 0) {
bundle.setValues(true);
+ } else if (strcmp(cp, "-include-meta-data") == 0) {
+ bundle.setIncludeMetaData(true);
} else if (strcmp(cp, "-custom-package") == 0) {
argc--;
argv++;
@@ -552,15 +571,24 @@ int main(int argc, char* const argv[])
bundle.setGenDependencies(true);
} else if (strcmp(cp, "-utf16") == 0) {
bundle.setWantUTF16(true);
- } else if (strcmp(cp, "-preferred-configurations") == 0) {
+ } else if (strcmp(cp, "-preferred-density") == 0) {
argc--;
argv++;
if (!argc) {
- fprintf(stderr, "ERROR: No argument supplied for '--preferred-configurations' option\n");
+ fprintf(stderr, "ERROR: No argument supplied for '--preferred-density' option\n");
wantUsage = true;
goto bail;
}
- bundle.addPreferredConfigurations(argv[0]);
+ bundle.setPreferredDensity(argv[0]);
+ } else if (strcmp(cp, "-split") == 0) {
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '--split' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ bundle.addSplitConfigurations(argv[0]);
} else if (strcmp(cp, "-rename-manifest-package") == 0) {
argc--;
argv++;
@@ -583,6 +611,8 @@ int main(int argc, char* const argv[])
bundle.setAutoAddOverlay(true);
} else if (strcmp(cp, "-error-on-failed-insert") == 0) {
bundle.setErrorOnFailedInsert(true);
+ } else if (strcmp(cp, "-error-on-missing-config-entry") == 0) {
+ bundle.setErrorOnMissingConfigEntry(true);
} else if (strcmp(cp, "-output-text-symbols") == 0) {
argc--;
argv++;
@@ -603,6 +633,9 @@ int main(int argc, char* const argv[])
bundle.setProduct(argv[0]);
} else if (strcmp(cp, "-non-constant-id") == 0) {
bundle.setNonConstantId(true);
+ } else if (strcmp(cp, "-shared-lib") == 0) {
+ bundle.setNonConstantId(true);
+ bundle.setBuildSharedLibrary(true);
} else if (strcmp(cp, "-no-crunch") == 0) {
bundle.setUseCrunchCache(true);
} else if (strcmp(cp, "-ignore-assets") == 0) {
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index a6b39ac..34c4496 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -10,8 +10,12 @@
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
-#include "Bundle.h"
+#include <utils/StrongPointer.h>
+
#include "AaptAssets.h"
+#include "ApkBuilder.h"
+#include "Bundle.h"
+#include "ResourceFilter.h"
#include "ZipFile.h"
@@ -22,6 +26,8 @@
#include <time.h>
#endif /* BENCHMARK */
+class OutputSet;
+
extern int doVersion(Bundle* bundle);
extern int doList(Bundle* bundle);
extern int doDump(Bundle* bundle);
@@ -34,13 +40,13 @@ extern int doSingleCrunch(Bundle* bundle);
extern int calcPercent(long uncompressedLen, long compressedLen);
extern android::status_t writeAPK(Bundle* bundle,
- const sp<AaptAssets>& assets,
- const android::String8& outputFile);
+ const android::String8& outputFile,
+ const android::sp<OutputSet>& outputSet);
extern android::status_t updatePreProcessedCache(Bundle* bundle);
extern android::status_t buildResources(Bundle* bundle,
- const sp<AaptAssets>& assets);
+ const sp<AaptAssets>& assets, sp<ApkBuilder>& builder);
extern android::status_t writeResourceSymbols(Bundle* bundle,
const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
@@ -49,8 +55,6 @@ extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>&
extern bool isValidResourceType(const String8& type);
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
-
extern status_t filterResources(Bundle* bundle, const sp<AaptAssets>& assets);
int dumpResources(Bundle* bundle);
diff --git a/tools/aapt/OutputSet.h b/tools/aapt/OutputSet.h
new file mode 100644
index 0000000..ea9ef70
--- /dev/null
+++ b/tools/aapt/OutputSet.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OUTPUT_SET_H
+#define __OUTPUT_SET_H
+
+#include <set>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+class AaptFile;
+
+class OutputEntry {
+public:
+ OutputEntry() {}
+ OutputEntry(const android::String8& path, const android::sp<const AaptFile>& file)
+ : mPath(path), mFile(file) {}
+
+ inline const android::sp<const AaptFile>& getFile() const {
+ return mFile;
+ }
+
+ inline const android::String8& getPath() const {
+ return mPath;
+ }
+
+ bool operator<(const OutputEntry& o) const { return getPath() < o.mPath; }
+ bool operator==(const OutputEntry& o) const { return getPath() == o.mPath; }
+
+private:
+ android::String8 mPath;
+ android::sp<const AaptFile> mFile;
+};
+
+class OutputSet : public virtual android::RefBase {
+public:
+ virtual const std::set<OutputEntry>& getEntries() const = 0;
+
+ virtual ~OutputSet() {}
+};
+
+#endif // __OUTPUT_SET_H
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 872d95c..dc16e35 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -5,6 +5,7 @@
//
#include "Main.h"
#include "AaptAssets.h"
+#include "OutputSet.h"
#include "ResourceTable.h"
#include "ResourceFilter.h"
@@ -36,11 +37,8 @@ static const char* kNoCompressExt[] = {
};
/* fwd decls, so I can write this downward */
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
- const AaptGroupEntry& ge, const ResourceFilter* filter);
-bool processFile(Bundle* bundle, ZipFile* zip,
- const sp<AaptGroup>& group, const sp<AaptFile>& file);
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet);
+bool processFile(Bundle* bundle, ZipFile* zip, String8 storageName, const sp<const AaptFile>& file);
bool okayToCompress(Bundle* bundle, const String8& pathName);
ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
@@ -51,8 +49,7 @@ ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
* On success, "bundle->numPackages" will be the number of Zip packages
* we created.
*/
-status_t writeAPK(Bundle* bundle, const sp<AaptAssets>& assets,
- const String8& outputFile)
+status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>& outputSet)
{
#if BENCHMARK
fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
@@ -112,7 +109,7 @@ status_t writeAPK(Bundle* bundle, const sp<AaptAssets>& assets,
printf("Writing all files...\n");
}
- count = processAssets(bundle, zip, assets);
+ count = processAssets(bundle, zip, outputSet);
if (count < 0) {
fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
outputFile.string());
@@ -218,72 +215,24 @@ bail:
return result;
}
-ssize_t processAssets(Bundle* bundle, ZipFile* zip,
- const sp<AaptAssets>& assets)
-{
- ResourceFilter filter;
- status_t status = filter.parse(bundle->getConfigurations());
- if (status != NO_ERROR) {
- return -1;
- }
-
- ssize_t count = 0;
-
- const size_t N = assets->getGroupEntries().size();
- for (size_t i=0; i<N; i++) {
- const AaptGroupEntry& ge = assets->getGroupEntries()[i];
-
- ssize_t res = processAssets(bundle, zip, assets, ge, &filter);
- if (res < 0) {
- return res;
- }
-
- count += res;
- }
-
- return count;
-}
-
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
- const AaptGroupEntry& ge, const ResourceFilter* filter)
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet)
{
ssize_t count = 0;
-
- const size_t ND = dir->getDirs().size();
- size_t i;
- for (i=0; i<ND; i++) {
- const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
-
- const bool filterable = filter != NULL && subDir->getLeaf().find("mipmap-") != 0;
-
- if (filterable && subDir->getLeaf() != subDir->getPath() && !filter->match(ge.toParams())) {
- continue;
- }
-
- ssize_t res = processAssets(bundle, zip, subDir, ge, filterable ? filter : NULL);
- if (res < 0) {
- return res;
- }
- count += res;
- }
-
- if (filter != NULL && !filter->match(ge.toParams())) {
- return count;
- }
-
- const size_t NF = dir->getFiles().size();
- for (i=0; i<NF; i++) {
- sp<AaptGroup> gp = dir->getFiles().valueAt(i);
- ssize_t fi = gp->getFiles().indexOfKey(ge);
- if (fi >= 0) {
- sp<AaptFile> fl = gp->getFiles().valueAt(fi);
- if (!processFile(bundle, zip, gp, fl)) {
+ const std::set<OutputEntry>& entries = outputSet->getEntries();
+ std::set<OutputEntry>::const_iterator iter = entries.begin();
+ for (; iter != entries.end(); iter++) {
+ const OutputEntry& entry = *iter;
+ if (entry.getFile() == NULL) {
+ fprintf(stderr, "warning: null file being processed.\n");
+ } else {
+ String8 storagePath(entry.getPath());
+ storagePath.convertToResPath();
+ if (!processFile(bundle, zip, storagePath, entry.getFile())) {
return UNKNOWN_ERROR;
}
count++;
}
}
-
return count;
}
@@ -294,12 +243,10 @@ ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
* delete the existing entry before adding the new one.
*/
bool processFile(Bundle* bundle, ZipFile* zip,
- const sp<AaptGroup>& group, const sp<AaptFile>& file)
+ String8 storageName, const sp<const AaptFile>& file)
{
const bool hasData = file->hasData();
- String8 storageName(group->getPath());
- storageName.convertToResPath();
ZipEntry* entry;
bool fromGzip = false;
status_t result;
@@ -403,8 +350,8 @@ bool processFile(Bundle* bundle, ZipFile* zip,
fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n",
file->getPrintableSource().string());
} else {
- fprintf(stderr, " Unable to add '%s': Zip add failed\n",
- file->getPrintableSource().string());
+ fprintf(stderr, " Unable to add '%s': Zip add failed (%d)\n",
+ file->getPrintableSource().string(), result);
}
return false;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 42b1905..e599643 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -179,24 +179,6 @@ bool isValidResourceType(const String8& type)
|| type == "color" || type == "menu" || type == "mipmap";
}
-static sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNecessary=true)
-{
- sp<AaptGroup> group = assets->getFiles().valueFor(String8("resources.arsc"));
- sp<AaptFile> file;
- if (group != NULL) {
- file = group->getFiles().valueFor(AaptGroupEntry());
- if (file != NULL) {
- return file;
- }
- }
-
- if (!makeIfNecessary) {
- return NULL;
- }
- return assets->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(),
- NULL, String8());
-}
-
static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
const sp<AaptGroup>& grp)
{
@@ -359,23 +341,6 @@ static status_t preProcessImages(const Bundle* bundle, const sp<AaptAssets>& ass
return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
}
-status_t postProcessImages(const sp<AaptAssets>& assets,
- ResourceTable* table,
- const sp<ResourceTypeSet>& set)
-{
- ResourceDirIterator it(set, String8("drawable"));
- bool hasErrors = false;
- ssize_t res;
- while ((res=it.next()) == NO_ERROR) {
- res = postProcessImage(assets, table, it.getFile());
- if (res < NO_ERROR) {
- hasErrors = true;
- }
- }
-
- return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
-}
-
static void collect_files(const sp<AaptDir>& dir,
KeyedVector<String8, sp<ResourceTypeSet> >* resources)
{
@@ -470,7 +435,7 @@ static int validateAttr(const String8& path, const ResTable& table,
value.data);
return ATTR_NOT_FOUND;
}
-
+
pool = table.getTableStringBlock(strIdx);
#if 0
if (pool != NULL) {
@@ -676,13 +641,15 @@ static bool applyFileOverlay(Bundle *bundle,
}
/*
- * Inserts an attribute in a given node, only if the attribute does not
- * exist.
+ * Inserts an attribute in a given node.
* If errorOnFailedInsert is true, and the attribute already exists, returns false.
- * Returns true otherwise, even if the attribute already exists.
+ * If replaceExisting is true, the attribute will be updated if it already exists.
+ * Returns true otherwise, even if the attribute already exists, and does not modify
+ * the existing attribute's value.
*/
bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
- const char* attr8, const char* value, bool errorOnFailedInsert)
+ const char* attr8, const char* value, bool errorOnFailedInsert,
+ bool replaceExisting)
{
if (value == NULL) {
return true;
@@ -691,7 +658,16 @@ bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
const String16 ns(ns8);
const String16 attr(attr8);
- if (node->getAttribute(ns, attr) != NULL) {
+ XMLNode::attribute_entry* existingEntry = node->editAttribute(ns, attr);
+ if (existingEntry != NULL) {
+ if (replaceExisting) {
+ NOISY(printf("Info: AndroidManifest.xml already defines %s (in %s);"
+ " overwriting existing value from manifest.\n",
+ String8(attr).string(), String8(ns).string()));
+ existingEntry->string = String16(value);
+ return true;
+ }
+
if (errorOnFailedInsert) {
fprintf(stderr, "Error: AndroidManifest.xml already defines %s (in %s);"
" cannot insert new value %s.\n",
@@ -706,11 +682,23 @@ bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
// don't stop the build.
return true;
}
-
+
node->addAttribute(ns, attr, String16(value));
return true;
}
+/*
+ * Inserts an attribute in a given node, only if the attribute does not
+ * exist.
+ * If errorOnFailedInsert is true, and the attribute already exists, returns false.
+ * Returns true otherwise, even if the attribute already exists.
+ */
+bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
+ const char* attr8, const char* value, bool errorOnFailedInsert)
+{
+ return addTagAttribute(node, ns8, attr8, value, errorOnFailedInsert, false);
+}
+
static void fullyQualifyClassName(const String8& package, sp<XMLNode> node,
const String16& attrName) {
XMLNode::attribute_entry* attr = node->editAttribute(
@@ -748,16 +736,17 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
}
bool errorOnFailedInsert = bundle->getErrorOnFailedInsert();
+ bool replaceVersion = bundle->getReplaceVersion();
if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
- bundle->getVersionCode(), errorOnFailedInsert)) {
+ bundle->getVersionCode(), errorOnFailedInsert, replaceVersion)) {
return UNKNOWN_ERROR;
}
if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
- bundle->getVersionName(), errorOnFailedInsert)) {
+ bundle->getVersionName(), errorOnFailedInsert, replaceVersion)) {
return UNKNOWN_ERROR;
}
-
+
if (bundle->getMinSdkVersion() != NULL
|| bundle->getTargetSdkVersion() != NULL
|| bundle->getMaxSdkVersion() != NULL) {
@@ -766,7 +755,7 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
root->insertChildAt(vers, 0);
}
-
+
if (!addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion",
bundle->getMinSdkVersion(), errorOnFailedInsert)) {
return UNKNOWN_ERROR;
@@ -841,7 +830,7 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
}
}
}
-
+
return NO_ERROR;
}
@@ -882,7 +871,38 @@ status_t updatePreProcessedCache(Bundle* bundle)
return 0;
}
-status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
+status_t generateAndroidManifestForSplit(const String16& package, const sp<ApkSplit>& split,
+ sp<AaptFile>& outFile) {
+ const String8 filename("AndroidManifest.xml");
+ const String16 androidPrefix("android");
+ const String16 androidNSUri("http://schemas.android.com/apk/res/android");
+ sp<XMLNode> root = XMLNode::newNamespace(filename, androidPrefix, androidNSUri);
+
+ // Build the <manifest> tag
+ sp<XMLNode> manifest = XMLNode::newElement(filename, String16(), String16("manifest"));
+
+ // Add the 'package' attribute which is set to the original package name.
+ manifest->addAttribute(String16(), String16("package"), package);
+
+ // Add the 'split' attribute which describes the configurations included.
+ String8 splitName("config_");
+ splitName.append(split->getDirectorySafeName());
+ manifest->addAttribute(String16(), String16("split"), String16(splitName));
+
+ // Build an empty <application> tag (required).
+ sp<XMLNode> app = XMLNode::newElement(filename, String16(), String16("application"));
+ manifest->addChild(app);
+ root->addChild(manifest);
+
+ status_t err = root->flatten(outFile, true, true);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ outFile->setCompressionMethod(ZipEntry::kCompressDeflated);
+ return NO_ERROR;
+}
+
+status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuilder>& builder)
{
// First, look for a package file to parse. This is required to
// be able to generate the resource information.
@@ -925,7 +945,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
// --------------------------------------------------------------
// resType -> leafName -> group
- KeyedVector<String8, sp<ResourceTypeSet> > *resources =
+ KeyedVector<String8, sp<ResourceTypeSet> > *resources =
new KeyedVector<String8, sp<ResourceTypeSet> >;
collect_files(assets, resources);
@@ -957,7 +977,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
// now go through any resource overlays and collect their files
sp<AaptAssets> current = assets->getOverlay();
while(current.get()) {
- KeyedVector<String8, sp<ResourceTypeSet> > *resources =
+ KeyedVector<String8, sp<ResourceTypeSet> > *resources =
new KeyedVector<String8, sp<ResourceTypeSet> >;
current->setResources(resources);
collect_files(current, resources);
@@ -1060,7 +1080,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
// compile resources
current = assets;
while(current.get()) {
- KeyedVector<String8, sp<ResourceTypeSet> > *resources =
+ KeyedVector<String8, sp<ResourceTypeSet> > *resources =
current->getResources();
ssize_t index = resources->indexOfKey(String8("values"));
@@ -1069,7 +1089,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
ssize_t res;
while ((res=it.next()) == NO_ERROR) {
sp<AaptFile> file = it.getFile();
- res = compileResourceFile(bundle, assets, file, it.getParams(),
+ res = compileResourceFile(bundle, assets, file, it.getParams(),
(current!=assets), &table);
if (res != NO_ERROR) {
hasErrors = true;
@@ -1098,12 +1118,6 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
// --------------------------------------------------------------------
if (table.hasResources()) {
- sp<AaptFile> resFile(getResourceFile(assets));
- if (resFile == NULL) {
- fprintf(stderr, "Error: unable to generate entry for resource data\n");
- return UNKNOWN_ERROR;
- }
-
err = table.assignResourceIds();
if (err < NO_ERROR) {
return err;
@@ -1211,16 +1225,24 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
}
if (drawables != NULL) {
- err = postProcessImages(assets, &table, drawables);
- if (err != NO_ERROR) {
+ ResourceDirIterator it(drawables, String8("drawable"));
+ while ((err=it.next()) == NO_ERROR) {
+ err = postProcessImage(assets, &table, it.getFile());
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (err < NO_ERROR) {
hasErrors = true;
}
+ err = NO_ERROR;
}
if (colors != NULL) {
ResourceDirIterator it(colors, String8("color"));
while ((err=it.next()) == NO_ERROR) {
- err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+ err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
if (err != NO_ERROR) {
hasErrors = true;
}
@@ -1255,7 +1277,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
if (table.validateLocalizations()) {
hasErrors = true;
}
-
+
if (hasErrors) {
return UNKNOWN_ERROR;
}
@@ -1288,7 +1310,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
ResTable finalResTable;
sp<AaptFile> resFile;
-
+
if (table.hasResources()) {
sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
err = table.addSymbols(symbols);
@@ -1296,15 +1318,35 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
return err;
}
- resFile = getResourceFile(assets);
- if (resFile == NULL) {
- fprintf(stderr, "Error: unable to generate entry for resource data\n");
- return UNKNOWN_ERROR;
- }
+ Vector<sp<ApkSplit> >& splits = builder->getSplits();
+ const size_t numSplits = splits.size();
+ for (size_t i = 0; i < numSplits; i++) {
+ sp<ApkSplit>& split = splits.editItemAt(i);
+ sp<AaptFile> flattenedTable = new AaptFile(String8("resources.arsc"),
+ AaptGroupEntry(), String8());
+ err = table.flatten(bundle, split->getResourceFilter(), flattenedTable);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed to generate resource table for split '%s'\n",
+ split->getPrintableName().string());
+ return err;
+ }
+ split->addEntry(String8("resources.arsc"), flattenedTable);
- err = table.flatten(bundle, resFile);
- if (err < NO_ERROR) {
- return err;
+ if (split->isBase()) {
+ resFile = flattenedTable;
+ finalResTable.add(flattenedTable->getData(), flattenedTable->getSize());
+ } else {
+ sp<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"),
+ AaptGroupEntry(), String8());
+ err = generateAndroidManifestForSplit(String16(assets->getPackage()), split,
+ generatedManifest);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed to generate AndroidManifest.xml for split '%s'\n",
+ split->getPrintableName().string());
+ return err;
+ }
+ split->addEntry(String8("AndroidManifest.xml"), generatedManifest);
+ }
}
if (bundle->getPublicOutputFile()) {
@@ -1321,14 +1363,10 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
fclose(fp);
}
- // Read resources back in,
- finalResTable.add(resFile->getData(), resFile->getSize());
-#if 0
- NOISY(
- printf("Generated resources:\n");
- finalResTable.print();
- )
-#endif
+ if (finalResTable.getTableCount() == 0 || resFile == NULL) {
+ fprintf(stderr, "No resource table was generated.\n");
+ return UNKNOWN_ERROR;
+ }
}
// Perform a basic validation of the manifest file. This time we
@@ -1425,7 +1463,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
ssize_t index = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "name");
const uint16_t* id = block.getAttributeStringValue(index, &len);
if (id == NULL) {
- fprintf(stderr, "%s:%d: missing name attribute in element <%s>.\n",
+ fprintf(stderr, "%s:%d: missing name attribute in element <%s>.\n",
manifestPath.string(), block.getLineNumber(),
String8(block.getElementName(&len)).string());
hasErrors = true;
@@ -1583,7 +1621,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
return err;
}
}
-
+
return err;
}
@@ -1705,7 +1743,7 @@ static status_t writeLayoutClasses(
NA = idents.size();
bool deprecated = false;
-
+
String16 comment = symbols->getComment(realClassName);
fprintf(fp, "%s/** ", indentStr);
if (comment.size() > 0) {
@@ -1788,7 +1826,7 @@ static status_t writeLayoutClasses(
if (deprecated) {
fprintf(fp, "%s@Deprecated\n", indentStr);
}
-
+
fprintf(fp,
"%spublic static final int[] %s = {\n"
"%s",
@@ -1833,9 +1871,9 @@ static status_t writeLayoutClasses(
//printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
// String8(attr16).string(), String8(name16).string(), typeSpecFlags);
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
-
+
bool deprecated = false;
-
+
fprintf(fp, "%s/**\n", indentStr);
if (comment.size() > 0) {
String8 cmt(comment);
@@ -2438,7 +2476,7 @@ struct NamespaceAttributePair {
status_t
writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
- const char* startTag, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
+ const Vector<String8>& startTags, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
{
status_t err;
ResXMLTree tree;
@@ -2452,15 +2490,18 @@ writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
tree.restart();
- if (startTag != NULL) {
+ if (!startTags.isEmpty()) {
bool haveStart = false;
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code != ResXMLTree::START_TAG) {
continue;
}
String8 tag(tree.getElementName(&len));
- if (tag == startTag) {
- haveStart = true;
+ const size_t numStartTags = startTags.size();
+ for (size_t i = 0; i < numStartTags; i++) {
+ if (tag == startTags[i]) {
+ haveStart = true;
+ }
}
break;
}
@@ -2547,15 +2588,17 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
for (size_t k=0; k<K; k++) {
const sp<AaptDir>& d = dirs.itemAt(k);
const String8& dirName = d->getLeaf();
+ Vector<String8> startTags;
const char* startTag = NULL;
const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
tagAttrPairs = &kLayoutTagAttrPairs;
} else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
- startTag = "PreferenceScreen";
+ startTags.add(String8("PreferenceScreen"));
+ startTags.add(String8("preference-headers"));
tagAttrPairs = &kXmlTagAttrPairs;
} else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
- startTag = "menu";
+ startTags.add(String8("menu"));
tagAttrPairs = NULL;
} else {
continue;
@@ -2568,7 +2611,7 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
const size_t M = files.size();
for (size_t j=0; j<M; j++) {
- err = writeProguardForXml(keep, files.valueAt(j), startTag, tagAttrPairs);
+ err = writeProguardForXml(keep, files.valueAt(j), startTags, tagAttrPairs);
if (err < 0) {
return err;
}
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index 8ca852e..de8b4fc 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -1,119 +1,92 @@
//
-// Copyright 2011 The Android Open Source Project
+// Copyright 2014 The Android Open Source Project
//
// Build resource files from raw assets.
//
#include "ResourceFilter.h"
+#include "AaptUtil.h"
+#include "AaptConfig.h"
status_t
-ResourceFilter::parse(const char* arg)
+WeakResourceFilter::parse(const String8& str)
{
- if (arg == NULL) {
- return 0;
- }
-
- const char* p = arg;
- const char* q;
-
- while (true) {
- q = strchr(p, ',');
- if (q == NULL) {
- q = p + strlen(p);
- }
-
- String8 part(p, q-p);
-
+ Vector<String8> configStrs = AaptUtil::split(str, ',');
+ const size_t N = configStrs.size();
+ mConfigs.clear();
+ mConfigMask = 0;
+ mConfigs.resize(N);
+ for (size_t i = 0; i < N; i++) {
+ const String8& part = configStrs[i];
if (part == "en_XA") {
mContainsPseudoAccented = true;
} else if (part == "ar_XB") {
mContainsPseudoBidi = true;
}
- int axis;
- AxisValue value;
- if (!AaptGroupEntry::parseFilterNamePart(part, &axis, &value)) {
- fprintf(stderr, "Invalid configuration: %s\n", arg);
- fprintf(stderr, " ");
- for (int i=0; i<p-arg; i++) {
- fprintf(stderr, " ");
- }
- for (int i=0; i<q-p; i++) {
- fprintf(stderr, "^");
- }
- fprintf(stderr, "\n");
- return 1;
- }
- ssize_t index = mData.indexOfKey(axis);
- if (index < 0) {
- mData.add(axis, SortedVector<AxisValue>());
- }
- SortedVector<AxisValue>& sv = mData.editValueFor(axis);
- sv.add(value);
+ std::pair<ConfigDescription, uint32_t>& entry = mConfigs.editItemAt(i);
- // If it's a locale with a region, script or variant, we should also match an
- // unmodified locale of the same language
- if (axis == AXIS_LOCALE) {
- if (value.localeValue.region[0] || value.localeValue.script[0] ||
- value.localeValue.variant[0]) {
- AxisValue copy;
- memcpy(copy.localeValue.language, value.localeValue.language,
- sizeof(value.localeValue.language));
- sv.add(copy);
- }
+ AaptLocaleValue val;
+ if (val.initFromFilterString(part)) {
+ // For backwards compatibility, we accept configurations that
+ // only specify locale in the standard 'en_US' format.
+ val.writeTo(&entry.first);
+ } else if (!AaptConfig::parse(part, &entry.first)) {
+ fprintf(stderr, "Invalid configuration: %s\n", part.string());
+ return UNKNOWN_ERROR;
}
- p = q;
- if (!*p) break;
- p++;
+
+ entry.second = mDefault.diff(entry.first);
+
+ // Ignore the version
+ entry.second &= ~ResTable_config::CONFIG_VERSION;
+
+ mConfigMask |= entry.second;
}
return NO_ERROR;
}
bool
-ResourceFilter::isEmpty() const
-{
- return mData.size() == 0;
-}
-
-bool
-ResourceFilter::match(int axis, const AxisValue& value) const
+WeakResourceFilter::match(const ResTable_config& config) const
{
- if (value.intValue == 0 && (value.localeValue.language[0] == 0)) {
- // they didn't specify anything so take everything
- return true;
- }
- ssize_t index = mData.indexOfKey(axis);
- if (index < 0) {
- // we didn't request anything on this axis so take everything
+ uint32_t mask = mDefault.diff(config);
+ if ((mConfigMask & mask) == 0) {
+ // The two configurations don't have any common axis.
return true;
}
- const SortedVector<AxisValue>& sv = mData.valueAt(index);
- return sv.indexOf(value) >= 0;
-}
-
-bool
-ResourceFilter::match(int axis, const ResTable_config& config) const
-{
- return match(axis, AaptGroupEntry::getConfigValueForAxis(config, axis));
-}
-bool
-ResourceFilter::match(const ResTable_config& config) const
-{
- for (int i=AXIS_START; i<=AXIS_END; i++) {
- if (!match(i, AaptGroupEntry::getConfigValueForAxis(config, i))) {
- return false;
+ const size_t N = mConfigs.size();
+ for (size_t i = 0; i < N; i++) {
+ const std::pair<ConfigDescription, uint32_t>& entry = mConfigs[i];
+ uint32_t diff = entry.first.diff(config);
+ if ((diff & entry.second) == 0) {
+ return true;
+ } else if ((diff & entry.second) == ResTable_config::CONFIG_LOCALE) {
+ // If the locales differ, but the languages are the same and
+ // the locale we are matching only has a language specified,
+ // we match.
+ if (config.language[0] && memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
+ if (config.country[0] == 0) {
+ return true;
+ }
+ }
}
}
- return true;
+ return false;
}
-const SortedVector<AxisValue>* ResourceFilter::configsForAxis(int axis) const
-{
- ssize_t index = mData.indexOfKey(axis);
- if (index < 0) {
- return NULL;
+status_t
+StrongResourceFilter::parse(const String8& str) {
+ Vector<String8> configStrs = AaptUtil::split(str, ',');
+ ConfigDescription config;
+ mConfigs.clear();
+ for (size_t i = 0; i < configStrs.size(); i++) {
+ if (!AaptConfig::parse(configStrs[i], &config)) {
+ fprintf(stderr, "Invalid configuration: %s\n", configStrs[i].string());
+ return UNKNOWN_ERROR;
+ }
+ mConfigs.insert(config);
}
- return &mData.valueAt(index);
+ return NO_ERROR;
}
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index c57770e..f459584 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -7,31 +7,137 @@
#ifndef RESOURCE_FILTER_H
#define RESOURCE_FILTER_H
+#include <androidfw/ResourceTypes.h>
+#include <set>
+#include <utility>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
#include "AaptAssets.h"
+#include "ConfigDescription.h"
+
+class ResourceFilter : public virtual android::RefBase {
+public:
+ virtual bool match(const android::ResTable_config& config) const = 0;
+};
/**
* Implements logic for parsing and handling "-c" and "--preferred-configurations"
* options.
*/
-class ResourceFilter
-{
+class WeakResourceFilter : public ResourceFilter {
public:
- ResourceFilter() : mData(), mContainsPseudoAccented(false),
- mContainsPseudoBidi(false) {}
- status_t parse(const char* arg);
- bool isEmpty() const;
- bool match(int axis, const ResTable_config& config) const;
- bool match(const ResTable_config& config) const;
- const SortedVector<AxisValue>* configsForAxis(int axis) const;
- inline bool containsPseudo() const { return mContainsPseudoAccented; }
- inline bool containsPseudoBidi() const { return mContainsPseudoBidi; }
+ WeakResourceFilter()
+ : mContainsPseudoAccented(false)
+ , mContainsPseudoBidi(false) {}
+
+ android::status_t parse(const android::String8& str);
+
+ bool match(const android::ResTable_config& config) const;
+
+ inline bool isEmpty() const {
+ return mConfigMask == 0;
+ }
+
+ inline bool containsPseudo() const {
+ return mContainsPseudoAccented;
+ }
+
+ inline bool containsPseudoBidi() const {
+ return mContainsPseudoBidi;
+ }
private:
- bool match(int axis, const AxisValue& value) const;
+ ConfigDescription mDefault;
+ uint32_t mConfigMask;
+ android::Vector<std::pair<ConfigDescription, uint32_t> > mConfigs;
- KeyedVector<int,SortedVector<AxisValue> > mData;
bool mContainsPseudoAccented;
bool mContainsPseudoBidi;
};
+/**
+ * Matches resources that have at least one of the configurations
+ * that this filter is looking for. In order to match a configuration,
+ * the resource must have the exact same configuration.
+ *
+ * This filter acts as a logical OR when matching resources.
+ *
+ * For example, if the filter is looking for resources with
+ * fr-land, de-land, or sw600dp:
+ *
+ * (PASS) fr-land
+ * (FAIL) fr
+ * (PASS) de-land
+ * (FAIL) de
+ * (FAIL) de-sw600dp
+ * (PASS) sw600dp
+ * (FAIL) sw600dp-land
+ */
+class StrongResourceFilter : public ResourceFilter {
+public:
+ StrongResourceFilter() {}
+ StrongResourceFilter(const std::set<ConfigDescription>& configs)
+ : mConfigs(configs) {}
+
+ android::status_t parse(const android::String8& str);
+
+ bool match(const android::ResTable_config& config) const {
+ std::set<ConfigDescription>::const_iterator iter = mConfigs.begin();
+ for (; iter != mConfigs.end(); iter++) {
+ if (iter->compare(config) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ inline const std::set<ConfigDescription>& getConfigs() const {
+ return mConfigs;
+ }
+
+private:
+ std::set<ConfigDescription> mConfigs;
+};
+
+/**
+ * Negates the response of the target filter.
+ */
+class InverseResourceFilter : public ResourceFilter {
+public:
+ InverseResourceFilter(const android::sp<ResourceFilter>& filter)
+ : mFilter(filter) {}
+
+ bool match(const android::ResTable_config& config) const {
+ return !mFilter->match(config);
+ }
+
+private:
+ const android::sp<ResourceFilter> mFilter;
+};
+
+/**
+ * A logical AND of all the added filters.
+ */
+class AndResourceFilter : public ResourceFilter {
+public:
+ void addFilter(const android::sp<ResourceFilter>& filter) {
+ mFilters.add(filter);
+ }
+
+ bool match(const android::ResTable_config& config) const {
+ const size_t N = mFilters.size();
+ for (size_t i = 0; i < N; i++) {
+ if (!mFilters[i]->match(config)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+ android::Vector<android::sp<ResourceFilter> > mFilters;
+};
#endif
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index e03f4f6..d60a07f 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -98,10 +98,10 @@ uint32_t ResourceIdCache::store(const android::String16& package,
void ResourceIdCache::dump() {
printf("ResourceIdCache dump:\n");
- printf("Size: %ld\n", mIdMap.size());
- printf("Hits: %ld\n", mHits);
- printf("Misses: %ld\n", mMisses);
- printf("(Collisions: %ld)\n", mCollisions);
+ printf("Size: %zd\n", mIdMap.size());
+ printf("Hits: %zd\n", mHits);
+ printf("Misses: %zd\n", mMisses);
+ printf("(Collisions: %zd)\n", mCollisions);
}
}
diff --git a/tools/aapt/ResourceIdCache.h b/tools/aapt/ResourceIdCache.h
index e6bcda2..3acdee1 100644
--- a/tools/aapt/ResourceIdCache.h
+++ b/tools/aapt/ResourceIdCache.h
@@ -6,18 +6,20 @@
#ifndef RESOURCE_ID_CACHE_H
#define RESOURCE_ID_CACHE_H
+#include <utils/String16.h>
+
namespace android {
class ResourceIdCache {
public:
- static uint32_t lookup(const android::String16& package,
- const android::String16& type,
- const android::String16& name,
+ static uint32_t lookup(const String16& package,
+ const String16& type,
+ const String16& name,
bool onlyPublic);
- static uint32_t store(const android::String16& package,
- const android::String16& type,
- const android::String16& name,
+ static uint32_t store(const String16& package,
+ const String16& type,
+ const String16& name,
bool onlyPublic,
uint32_t resId);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index cf271a9..efbba40 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1715,7 +1715,7 @@ status_t compileResourceFile(Bundle* bundle,
ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage)
: mAssetsPackage(assetsPackage), mNextPackageId(1), mHaveAppPackage(false),
- mIsAppPackage(!bundle->getExtending()),
+ mIsAppPackage(!bundle->getExtending()), mIsSharedLibrary(bundle->getBuildSharedLibrary()),
mNumLocal(0),
mBundle(bundle)
{
@@ -1737,8 +1737,9 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets
const size_t N = incl.getBasePackageCount();
for (size_t phase=0; phase<2; phase++) {
for (size_t i=0; i<N; i++) {
- String16 name(incl.getBasePackageName(i));
+ const String16 name = incl.getBasePackageName(i);
uint32_t id = incl.getBasePackageId(i);
+
// First time through: only add base packages (id
// is not 0); second time through add the other
// packages.
@@ -1764,7 +1765,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets
}
}
if (id != 0) {
- NOISY(printf("Including package %s with ID=%d\n",
+ NOISY(fprintf(stderr, "Including package %s with ID=%d\n",
String8(name).string(), id));
sp<Package> p = new Package(name, id);
mPackages.add(name, p);
@@ -2094,10 +2095,10 @@ bool ResourceTable::hasResources() const {
return mNumLocal > 0;
}
-sp<AaptFile> ResourceTable::flatten(Bundle* bundle)
+sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter)
{
sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
- status_t err = flatten(bundle, data);
+ status_t err = flatten(bundle, filter, data);
return err == NO_ERROR ? data : NULL;
}
@@ -2657,8 +2658,8 @@ ResourceTable::validateLocalizations(void)
}
// Check that all requested localizations are present for this string
- if (mBundle->getConfigurations() != NULL && mBundle->getRequireLocalization()) {
- const char* allConfigs = mBundle->getConfigurations();
+ if (mBundle->getConfigurations().size() > 0 && mBundle->getRequireLocalization()) {
+ const char* allConfigs = mBundle->getConfigurations().string();
const char* start = allConfigs;
const char* comma;
@@ -2712,14 +2713,8 @@ ResourceTable::validateLocalizations(void)
return err;
}
-status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
+status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest)
{
- ResourceFilter filter;
- status_t err = filter.parse(bundle->getConfigurations());
- if (err != NO_ERROR) {
- return err;
- }
-
const ConfigDescription nullConfig;
const size_t N = mOrderedPackages.size();
@@ -2729,6 +2724,9 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
bool useUTF8 = !bundle->getUTF16StringsOption();
+ // The libraries this table references.
+ Vector<sp<Package> > libraryPackages;
+
// Iterate through all data, collecting all values (strings,
// references, etc).
StringPool valueStrings(useUTF8);
@@ -2736,8 +2734,22 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
for (pi=0; pi<N; pi++) {
sp<Package> p = mOrderedPackages.itemAt(pi);
if (p->getTypes().size() == 0) {
- // Empty, skip!
+ // Empty, this is an imported package being used as
+ // a shared library. We do not flatten this package.
+ if (p->getAssignedId() != 0x01 && p->getName() != String16("android")) {
+ // This is not the base Android package, and it is a library
+ // so we must add a reference to the library when flattening.
+ libraryPackages.add(p);
+ }
continue;
+ } else if (p->getAssignedId() == 0x00) {
+ if (!bundle->getBuildSharedLibrary()) {
+ fprintf(stderr, "ERROR: Package %s can not have ID=0x00 unless building a shared library.",
+ String8(p->getName()).string());
+ return UNKNOWN_ERROR;
+ }
+ // If this is a shared library, we also include ourselves as an entry.
+ libraryPackages.add(p);
}
StringPool typeStrings(useUTF8);
@@ -2777,7 +2789,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
const size_t N = c->getEntries().size();
for (size_t ei=0; ei<N; ei++) {
ConfigDescription config = c->getEntries().keyAt(ei);
- if (filterable && !filter.match(config)) {
+ if (filterable && !filter->match(config)) {
continue;
}
sp<Entry> e = c->getEntries().valueAt(ei);
@@ -2820,7 +2832,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
}
ssize_t strAmt = 0;
-
+
// Now build the array of package chunks.
Vector<sp<AaptFile> > flatPackages;
for (pi=0; pi<N; pi++) {
@@ -2869,6 +2881,12 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
return amt;
}
+ status_t err = flattenLibraryTable(data, libraryPackages);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: failed to write library table\n");
+ return err;
+ }
+
// Build the type chunks inside of this package.
for (size_t ti=0; ti<N; ti++) {
// Retrieve them in the same order as the type string block.
@@ -2919,11 +2937,11 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
}
const size_t CN = cl->getEntries().size();
for (size_t ci=0; ci<CN; ci++) {
- if (filterable && !filter.match(cl->getEntries().keyAt(ci))) {
+ if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
continue;
}
for (size_t cj=ci+1; cj<CN; cj++) {
- if (filterable && !filter.match(cl->getEntries().keyAt(cj))) {
+ if (filterable && !filter->match(cl->getEntries().keyAt(cj))) {
continue;
}
typeSpecFlags[ei] |= htodl(
@@ -2965,7 +2983,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
config.screenHeightDp,
config.layoutDirection));
- if (filterable && !filter.match(config)) {
+ if (filterable && !filter->match(config)) {
continue;
}
@@ -3038,13 +3056,21 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
tHeader->header.size = htodl(data->getSize()-typeStart);
}
+ bool missing_entry = false;
+ const char* log_prefix = bundle->getErrorOnMissingConfigEntry() ?
+ "error" : "warning";
for (size_t i = 0; i < N; ++i) {
if (!validResources[i]) {
sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
- fprintf(stderr, "warning: no entries written for %s/%s\n",
+ fprintf(stderr, "%s: no entries written for %s/%s\n", log_prefix,
String8(typeName).string(), String8(c->getName()).string());
+ missing_entry = true;
}
}
+ if (bundle->getErrorOnMissingConfigEntry() && missing_entry) {
+ fprintf(stderr, "Error: Missing entries, quit!\n");
+ return NOT_ENOUGH_DATA;
+ }
}
// Fill in the rest of the package information.
@@ -3076,7 +3102,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
}
ssize_t strStart = dest->getSize();
- err = valueStrings.writeStringBlock(dest);
+ status_t err = valueStrings.writeStringBlock(dest);
if (err != NO_ERROR) {
return err;
}
@@ -3087,7 +3113,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
fprintf(stderr, "**** value strings: %d\n", amt);
fprintf(stderr, "**** total strings: %d\n", strAmt);
#endif
-
+
for (pi=0; pi<flatPackages.size(); pi++) {
err = dest->writeData(flatPackages[pi]->getData(),
flatPackages[pi]->getSize());
@@ -3112,6 +3138,38 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
return NO_ERROR;
}
+status_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs) {
+ // Write out the library table if necessary
+ if (libs.size() > 0) {
+ NOISY(fprintf(stderr, "Writing library reference table\n"));
+
+ const size_t libStart = dest->getSize();
+ const size_t count = libs.size();
+ ResTable_lib_header* libHeader = (ResTable_lib_header*) dest->editDataInRange(libStart, sizeof(ResTable_lib_header));
+
+ memset(libHeader, 0, sizeof(*libHeader));
+ libHeader->header.type = htods(RES_TABLE_LIBRARY_TYPE);
+ libHeader->header.headerSize = htods(sizeof(*libHeader));
+ libHeader->header.size = htodl(sizeof(*libHeader) + (sizeof(ResTable_lib_entry) * count));
+ libHeader->count = htodl(count);
+
+ // Write the library entries
+ for (size_t i = 0; i < count; i++) {
+ const size_t entryStart = dest->getSize();
+ sp<Package> libPackage = libs[i];
+ NOISY(fprintf(stderr, " Entry %s -> 0x%02x\n",
+ String8(libPackage->getName()).string(),
+ (uint8_t)libPackage->getAssignedId()));
+
+ ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(entryStart, sizeof(ResTable_lib_entry));
+ memset(entry, 0, sizeof(*entry));
+ entry->packageId = htodl(libPackage->getAssignedId());
+ strcpy16_htod(entry->packageName, libPackage->getName().string());
+ }
+ }
+ return NO_ERROR;
+}
+
void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp)
{
fprintf(fp,
@@ -3881,7 +3939,7 @@ sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
return NULL;
}
mHaveAppPackage = true;
- p = new Package(package, 127);
+ p = new Package(package, mIsSharedLibrary ? 0 : 127);
} else {
p = new Package(package, mNextPackageId);
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 75005cd..a73993c 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -7,8 +7,10 @@
#ifndef RESOURCE_TABLE_H
#define RESOURCE_TABLE_H
+#include "ConfigDescription.h"
#include "StringPool.h"
#include "SourcePos.h"
+#include "ResourceFilter.h"
#include <set>
#include <map>
@@ -76,37 +78,6 @@ public:
class Type;
class Entry;
- struct ConfigDescription : public ResTable_config {
- ConfigDescription() {
- memset(this, 0, sizeof(*this));
- size = sizeof(ResTable_config);
- }
- ConfigDescription(const ResTable_config&o) {
- *static_cast<ResTable_config*>(this) = o;
- size = sizeof(ResTable_config);
- }
- ConfigDescription(const ConfigDescription&o) {
- *static_cast<ResTable_config*>(this) = o;
- }
-
- ConfigDescription& operator=(const ResTable_config& o) {
- *static_cast<ResTable_config*>(this) = o;
- size = sizeof(ResTable_config);
- return *this;
- }
- ConfigDescription& operator=(const ConfigDescription& o) {
- *static_cast<ResTable_config*>(this) = o;
- return *this;
- }
-
- inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
- inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
- inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
- inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
- inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
- inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
- };
-
ResourceTable(Bundle* bundle, const String16& assetsPackage);
status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
@@ -182,7 +153,7 @@ public:
size_t numLocalResources() const;
bool hasResources() const;
- sp<AaptFile> flatten(Bundle*);
+ sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter);
static inline uint32_t makeResId(uint32_t packageId,
uint32_t typeId,
@@ -223,7 +194,8 @@ public:
void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
status_t validateLocalizations(void);
- status_t flatten(Bundle*, const sp<AaptFile>& dest);
+ status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest);
+ status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
void writePublicDefinitions(const String16& package, FILE* fp);
@@ -546,6 +518,7 @@ private:
uint32_t mNextPackageId;
bool mHaveAppPackage;
bool mIsAppPackage;
+ bool mIsSharedLibrary;
size_t mNumLocal;
SourcePos mCurrentXmlPos;
Bundle* mBundle;
diff --git a/tools/aapt/printapk.cpp b/tools/aapt/printapk.cpp
index 4cf73d8..def6e2e 100644
--- a/tools/aapt/printapk.cpp
+++ b/tools/aapt/printapk.cpp
@@ -115,8 +115,8 @@ main(int argc, char** argv)
size_t basePackageCount = res.getBasePackageCount();
printf("Base Packages: %d\n", (int)basePackageCount);
for (size_t bpIndex=0; bpIndex<basePackageCount; bpIndex++) {
- const char16_t* ch = res.getBasePackageName(bpIndex);
- String8 s = String8(String16(ch));
+ const String16 ch = res.getBasePackageName(bpIndex);
+ String8 s = String8(ch);
printf(" [%3d] %s\n", (int)bpIndex, s.string());
}
#endif
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
new file mode 100644
index 0000000..e795d81
--- /dev/null
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptConfig.h"
+#include "ConfigDescription.h"
+#include "TestHelper.h"
+
+using android::String8;
+
+static ::testing::AssertionResult TestParse(const String8& input, ConfigDescription* config=NULL) {
+ if (AaptConfig::parse(String8(input), config)) {
+ return ::testing::AssertionSuccess() << input << " was successfully parsed";
+ }
+ return ::testing::AssertionFailure() << input << " could not be parsed";
+}
+
+static ::testing::AssertionResult TestParse(const char* input, ConfigDescription* config=NULL) {
+ return TestParse(String8(input), config);
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersAreOutOfOrder) {
+ EXPECT_FALSE(TestParse("en-sw600dp-ldrtl"));
+ EXPECT_FALSE(TestParse("land-en"));
+ EXPECT_FALSE(TestParse("hdpi-320dpi"));
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersAreNotMatched) {
+ EXPECT_FALSE(TestParse("en-sw600dp-ILLEGAL"));
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersHaveTrailingDash) {
+ EXPECT_FALSE(TestParse("en-sw600dp-land-"));
+}
+
+TEST(AaptConfigTest, ParseBasicQualifiers) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("", &config));
+ EXPECT_EQ(String8(""), config.toString());
+
+ EXPECT_TRUE(TestParse("fr-land", &config));
+ EXPECT_EQ(String8("fr-land"), config.toString());
+
+ EXPECT_TRUE(TestParse("mcc310-pl-sw720dp-normal-long-port-night-"
+ "xhdpi-keyssoft-qwerty-navexposed-nonav", &config));
+ EXPECT_EQ(String8("mcc310-pl-sw720dp-normal-long-port-night-"
+ "xhdpi-keyssoft-qwerty-navexposed-nonav-v13"), config.toString());
+}
+
+TEST(AaptConfigTest, ParseLocales) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("en-rUS", &config));
+ EXPECT_EQ(String8("en-US"), config.toString());
+}
+
+TEST(AaptConfigTest, ParseQualifierAddedInApi13) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("sw600dp", &config));
+ EXPECT_EQ(String8("sw600dp-v13"), config.toString());
+
+ EXPECT_TRUE(TestParse("sw600dp-v8", &config));
+ EXPECT_EQ(String8("sw600dp-v13"), config.toString());
+}
diff --git a/tools/aapt/tests/AaptGroupEntry_test.cpp b/tools/aapt/tests/AaptGroupEntry_test.cpp
new file mode 100644
index 0000000..7348a08
--- /dev/null
+++ b/tools/aapt/tests/AaptGroupEntry_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptAssets.h"
+#include "ResourceFilter.h"
+#include "TestHelper.h"
+
+using android::String8;
+
+static ::testing::AssertionResult TestParse(AaptGroupEntry& entry, const String8& dirName,
+ String8* outType) {
+ if (entry.initFromDirName(dirName, outType)) {
+ return ::testing::AssertionSuccess() << dirName << " was successfully parsed";
+ }
+ return ::testing::AssertionFailure() << dirName << " could not be parsed";
+}
+
+static ::testing::AssertionResult TestParse(AaptGroupEntry& entry, const char* input,
+ String8* outType) {
+ return TestParse(entry, String8(input), outType);
+}
+
+TEST(AaptGroupEntryTest, ParseNoQualifier) {
+ AaptGroupEntry entry;
+ String8 type;
+ EXPECT_TRUE(TestParse(entry, "menu", &type));
+ EXPECT_EQ(String8("menu"), type);
+}
+
+TEST(AaptGroupEntryTest, ParseCorrectType) {
+ AaptGroupEntry entry;
+ String8 type;
+ EXPECT_TRUE(TestParse(entry, "anim", &type));
+ EXPECT_EQ(String8("anim"), type);
+
+ EXPECT_TRUE(TestParse(entry, "animator", &type));
+ EXPECT_EQ(String8("animator"), type);
+}
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
new file mode 100644
index 0000000..30697bb
--- /dev/null
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptConfig.h"
+#include "ResourceFilter.h"
+#include "ConfigDescription.h"
+
+using android::String8;
+
+// In this context, 'Axis' represents a particular field in the configuration,
+// such as language or density.
+
+TEST(WeakResourceFilterTest, EmptyFilterMatchesAnything) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("")));
+
+ ConfigDescription config;
+ config.density = 320;
+
+ EXPECT_TRUE(filter.match(config));
+
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithUnrelatedAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.density = 320;
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameValueAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameValueAxisAndOtherUnrelatedAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+ config.density = 320;
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, DoesNotMatchConfigWithDifferentValueAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.language[0] = 'd';
+ config.language[1] = 'e';
+
+ EXPECT_FALSE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameLanguageButNoRegionSpecified) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("de-rDE")));
+
+ ConfigDescription config;
+ config.language[0] = 'd';
+ config.language[1] = 'e';
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, ParsesStandardLocaleOnlyString) {
+ WeakResourceFilter filter;
+ EXPECT_EQ(NO_ERROR, filter.parse(String8("de_DE")));
+}
+
+TEST(WeakResourceFilterTest, IgnoresVersion) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("normal-v4")));
+
+ ConfigDescription config;
+ config.smallestScreenWidthDp = 600;
+ config.version = 13;
+
+ // The configs don't match on any axis besides version, which should be ignored.
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithRegion) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("kok,kok_IN,kok_419")));
+
+ ConfigDescription config;
+ AaptLocaleValue val;
+ ASSERT_TRUE(val.initFromFilterString(String8("kok_IN")));
+ val.writeTo(&config);
+
+ EXPECT_TRUE(filter.match(config));
+}
+
diff --git a/tools/aapt/tests/TestHelper.h b/tools/aapt/tests/TestHelper.h
new file mode 100644
index 0000000..7917483
--- /dev/null
+++ b/tools/aapt/tests/TestHelper.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TEST_HELPER_H
+#define __TEST_HELPER_H
+
+#include <utils/String8.h>
+
+namespace android {
+
+/**
+ * Stream operator for nicely printing String8's in gtest output.
+ */
+inline std::ostream& operator<<(std::ostream& stream, const String8& str) {
+ return stream << str.string();
+}
+
+}
+
+#endif
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index a84d743..9c1867e 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -207,7 +207,7 @@ check_filename(const char* filename, const char* package, buffer_type* name)
p = strchr(name->data, '.');
len = p ? p-name->data : strlen(name->data);
expected.append(name->data, len);
-
+
expected += ".aidl";
len = fn.length();
@@ -473,7 +473,7 @@ check_method(const char* filename, int kind, method_type* m)
err = 1;
goto next;
}
-
+
if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
filename, m->type.type.lineno, index,
@@ -536,7 +536,7 @@ check_method(const char* filename, int kind, method_type* m)
filename, m->name.lineno, index, arg->name.data);
err = 1;
}
-
+
next:
index++;
arg = arg->next;
@@ -797,7 +797,7 @@ parse_preprocessed_file(const string& filename)
//printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
// type, packagename, classname);
document_item_type* doc;
-
+
if (0 == strcmp("parcelable", type)) {
user_data_type* parcl = (user_data_type*)malloc(
sizeof(user_data_type));
@@ -1104,13 +1104,13 @@ preprocess_aidl(const Options& options)
}
// write preprocessed file
- int fd = open( options.outputFileName.c_str(),
+ int fd = open( options.outputFileName.c_str(),
O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
#ifdef HAVE_MS_C_RUNTIME
_S_IREAD|_S_IWRITE);
-#else
+#else
S_IRUSR|S_IWUSR|S_IRGRP);
-#endif
+#endif
if (fd == -1) {
fprintf(stderr, "aidl: could not open file for write: %s\n",
options.outputFileName.c_str());
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 2e4274d..aef3efa 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry excluding="org/kxml2/io/" kind="src" path="src"/>
+ <classpathentry kind="src" path="tests/src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar" sourcepath="/ANDROID_SRC/tools/base/layoutlib-api/src/main"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/icu4j/icu4j.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
index 224eac6..4603b63 100644
--- a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -48,6 +48,20 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
}
@LayoutlibDelegate
+ /*package*/ static long nGetMultipleIntMethod(Class<?> targetClass, String methodName,
+ int numParams) {
+ // TODO: return the right thing.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nGetMultipleFloatMethod(Class<?> targetClass, String methodName,
+ int numParams) {
+ // TODO: return the right thing.
+ return 0;
+ }
+
+ @LayoutlibDelegate
/*package*/ static void nCallIntMethod(Object target, long methodID, int arg) {
// do nothing
}
@@ -56,4 +70,40 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/*package*/ static void nCallFloatMethod(Object target, long methodID, float arg) {
// do nothing
}
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallTwoIntMethod(Object target, long methodID, int arg1,
+ int arg2) {
+ // do nothing
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallFourIntMethod(Object target, long methodID, int arg1,
+ int arg2, int arg3, int arg4) {
+ // do nothing
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallMultipleIntMethod(Object target, long methodID,
+ int[] args) {
+ // do nothing
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallTwoFloatMethod(Object target, long methodID, float arg1,
+ float arg2) {
+ // do nothing
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallFourFloatMethod(Object target, long methodID, float arg1,
+ float arg2, float arg3, float arg4) {
+ // do nothing
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallMultipleFloatMethod(Object target, long methodID,
+ float[] args) {
+ // do nothing
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
index 5c2b793..914a359 100644
--- a/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
@@ -40,9 +40,6 @@ public class AssetManager_Delegate {
@LayoutlibDelegate
/*package*/ static void applyThemeStyle(long theme, int styleRes, boolean force) {
- Resources_Theme_Delegate delegate = Resources_Theme_Delegate.getDelegateManager()
- .getDelegate(theme);
- delegate.mThemeResId = styleRes;
- delegate.force = force;
+ Resources_Theme_Delegate.getDelegateManager().getDelegate(theme).force = force;
}
}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 8794452..dd573be 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -51,6 +51,7 @@ public final class BridgeResources extends Resources {
private BridgeContext mContext;
private IProjectCallback mProjectCallback;
private boolean[] mPlatformResourceFlag = new boolean[1];
+ private TypedValue mTmpValue = new TypedValue();
/**
* Simpler wrapper around FileInputStream. This is used when the input stream represent
@@ -154,6 +155,11 @@ public final class BridgeResources extends Resources {
@Override
public Drawable getDrawable(int id) throws NotFoundException {
+ return getDrawable(id, null);
+ }
+
+ @Override
+ public Drawable getDrawable(int id, Theme theme) {
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 446d139..cc621c4 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -52,13 +52,13 @@ public final class BridgeTypedArray extends TypedArray {
private final BridgeContext mContext;
private final boolean mPlatformFile;
- private ResourceValue[] mResourceData;
- private String[] mNames;
- private boolean[] mIsFramework;
+ private final ResourceValue[] mResourceData;
+ private final String[] mNames;
+ private final boolean[] mIsFramework;
public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
boolean platformFile) {
- super(null, null, null, 0);
+ super(resources, null, null, 0);
mBridgeResources = resources;
mContext = context;
mPlatformFile = platformFile;
@@ -81,8 +81,8 @@ public final class BridgeTypedArray extends TypedArray {
}
/**
- * Seals the array after all calls to {@link #bridgeSetValue(int, String, ResourceValue)} have
- * been done.
+ * Seals the array after all calls to
+ * {@link #bridgeSetValue(int, String, boolean, ResourceValue)} have been done.
* <p/>This allows to compute the list of non default values, permitting
* {@link #getIndexCount()} to return the proper value.
*/
@@ -252,7 +252,7 @@ public final class BridgeTypedArray extends TypedArray {
for (String keyword : keywords) {
Integer i = map.get(keyword.trim());
if (i != null) {
- result |= i.intValue();
+ result |= i;
} else {
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
String.format(
@@ -731,7 +731,7 @@ public final class BridgeTypedArray extends TypedArray {
}
// not a direct id valid reference? resolve it
- Integer idValue = null;
+ Integer idValue;
if (resValue.isFramework()) {
idValue = Bridge.getResourceId(resValue.getResourceType(),
@@ -742,7 +742,7 @@ public final class BridgeTypedArray extends TypedArray {
}
if (idValue != null) {
- return idValue.intValue();
+ return idValue;
}
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
@@ -753,6 +753,12 @@ public final class BridgeTypedArray extends TypedArray {
return defValue;
}
+ @Override
+ public int getThemeAttributeId(int index, int defValue) {
+ // TODO: Get the right Theme Attribute ID to enable caching of the drawables.
+ return defValue;
+ }
+
/**
* Retrieve the Drawable for the attribute at <var>index</var>. This
* gets the resource ID of the selected attribute, and uses
@@ -854,6 +860,7 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public boolean hasValue(int index) {
+ //noinspection SimplifiableIfStatement
if (index < 0 || index >= mResourceData.length) {
return false;
}
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
new file mode 100644
index 0000000..112250d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import java.util.Locale;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.ibm.icu.util.ULocale;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Resources}
+ *
+ * Through the layoutlib_create tool, the original methods of Resources have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class Resources_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static String localeToLanguageTag(Resources res, Locale locale) {
+ return ULocale.forLocale(locale).toLanguageTag();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
index b89d15f..31d1594 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -39,8 +39,6 @@ import android.util.TypedValue;
*/
public class Resources_Theme_Delegate {
- // Resource identifier for the theme.
- int mThemeResId;
// Whether to use the Theme.mThemeResId as primary theme.
boolean force;
@@ -103,7 +101,7 @@ public class Resources_Theme_Delegate {
private static boolean setupResources(Theme thisTheme) {
Resources_Theme_Delegate themeDelegate = sManager.getDelegate(thisTheme.getNativeTheme());
- StyleResourceValue style = resolveStyle(themeDelegate.mThemeResId);
+ StyleResourceValue style = resolveStyle(thisTheme.getAppliedStyleResId());
if (style != null) {
RenderSessionImpl.getCurrentContext().getRenderResources()
.applyStyle(style, themeDelegate.force);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 73d274c..56c0de9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -71,7 +71,7 @@ public final class Canvas_Delegate {
* Returns the native delegate associated to a given {@link Canvas} object.
*/
public static Canvas_Delegate getDelegate(Canvas canvas) {
- return sManager.getDelegate(canvas.mNativeCanvas);
+ return sManager.getDelegate(canvas.getNativeCanvas());
}
/**
@@ -102,7 +102,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static boolean isOpaque(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return false;
}
@@ -113,7 +113,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static int getWidth(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -124,7 +124,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static int getHeight(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -135,7 +135,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -146,7 +146,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void rotate(Canvas thisCanvas, float degrees) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -157,7 +157,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -168,7 +168,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -204,7 +204,7 @@ public final class Canvas_Delegate {
/*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
float bottom) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return false;
}
@@ -227,7 +227,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static int save(Canvas thisCanvas, int saveFlags) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -238,7 +238,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void restore(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -249,7 +249,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static int getSaveCount(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -260,7 +260,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -287,7 +287,7 @@ public final class Canvas_Delegate {
/*package*/ static void drawLines(Canvas thisCanvas,
final float[] pts, final int offset, final int count,
Paint paint) {
- draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
+ draw(thisCanvas.getNativeCanvas(), paint.mNativePaint, false /*compositeOnly*/,
false /*forceSrcMode*/, new GcSnapshot.Drawable() {
@Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
@@ -344,7 +344,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayer(long nativeCanvas, RectF bounds,
+ /*package*/ static int native_saveLayer(long nativeCanvas, RectF bounds,
long paint, int layerFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -361,7 +361,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayer(long nativeCanvas, float l,
+ /*package*/ static int native_saveLayer(long nativeCanvas, float l,
float t, float r, float b,
long paint, int layerFlags) {
// get the delegate from the native int.
@@ -380,7 +380,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayerAlpha(long nativeCanvas,
+ /*package*/ static int native_saveLayerAlpha(long nativeCanvas,
RectF bounds, int alpha,
int layerFlags) {
// get the delegate from the native int.
@@ -393,7 +393,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayerAlpha(long nativeCanvas, float l,
+ /*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags) {
// get the delegate from the native int.
@@ -757,7 +757,8 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void native_drawRoundRect(long nativeCanvas,
- final RectF rect, final float rx, final float ry, long paint) {
+ final float left, final float top, final float right, final float bottom,
+ final float rx, final float ry, long paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@@ -769,16 +770,16 @@ public final class Canvas_Delegate {
if (style == Paint.Style.FILL.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
graphics.fillRoundRect(
- (int)rect.left, (int)rect.top,
- (int)rect.width(), (int)rect.height(),
+ (int)left, (int)top,
+ (int)(right - left), (int)(bottom - top),
(int)rx, (int)ry);
}
if (style == Paint.Style.STROKE.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
graphics.drawRoundRect(
- (int)rect.left, (int)rect.top,
- (int)rect.width(), (int)rect.height(),
+ (int)left, (int)top,
+ (int)(right - left), (int)(bottom - top),
(int)rx, (int)ry);
}
}
@@ -975,8 +976,10 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void native_drawText(long nativeCanvas,
final char[] text, final int index, final int count,
- final float startX, final float startY, final int flags, long paint) {
+ final float startX, final float startY, final int flags, long paint,
+ long typeface) {
+ // TODO: use typeface.
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@Override
@@ -1006,30 +1009,31 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void native_drawText(long nativeCanvas, String text,
- int start, int end, float x, float y, final int flags, long paint) {
+ int start, int end, float x, float y, final int flags, long paint,
+ long typeface) {
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
- native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
+ native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
}
@LayoutlibDelegate
/*package*/ static void native_drawTextRun(long nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
- float x, float y, int flags, long paint) {
+ float x, float y, int flags, long paint, long typeface) {
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
- native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
+ native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface);
}
@LayoutlibDelegate
/*package*/ static void native_drawTextRun(long nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
- float x, float y, int flags, long paint) {
- native_drawText(nativeCanvas, text, start, count, x, y, flags, paint);
+ float x, float y, int flags, long paint, long typeface) {
+ native_drawText(nativeCanvas, text, start, count, x, y, flags, paint, typeface);
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index d6b3da1..bf03a5e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -56,7 +56,7 @@ public abstract class ColorFilter_Delegate {
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static void finalizer(long native_instance, long nativeColorFilter) {
+ /*package*/ static void destroyFilter(long native_instance) {
sManager.removeJavaReferenceFor(native_instance);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
index ca8f450..9aac2bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -60,11 +60,5 @@ public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate {
return sManager.addNewDelegate(newDelegate);
}
- @LayoutlibDelegate
- /*package*/ static long nColorMatrixFilter(long nativeFilter, float[] array) {
- // pass
- return 0;
- }
-
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
index defaac3..501d55c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -60,11 +60,5 @@ public class LightingColorFilter_Delegate extends ColorFilter_Delegate {
return sManager.addNewDelegate(newDelegate);
}
- @LayoutlibDelegate
- /*package*/ static int nCreateLightingFilter(long nativeFilter, int mul, int add) {
- // pass
- return 0;
- }
-
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index ebfe9bc..8862f5b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -355,227 +355,162 @@ public final class Matrix_Delegate {
}
@LayoutlibDelegate
- /*package*/ static boolean native_setConcat(long native_object, long a, long b) {
+ /*package*/ static void native_setConcat(long native_object, long a, long b) {
if (a == native_object) {
- return native_preConcat(native_object, b);
+ native_preConcat(native_object, b);
+ return;
} else if (b == native_object) {
- return native_postConcat(native_object, a);
+ native_postConcat(native_object, a);
+ return;
}
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
- }
-
Matrix_Delegate a_mtx = sManager.getDelegate(a);
- if (a_mtx == null) {
- return false;
- }
-
Matrix_Delegate b_mtx = sManager.getDelegate(b);
- if (b_mtx == null) {
- return false;
+ if (d != null && a_mtx != null && b_mtx != null) {
+ multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
}
-
- multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
-
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preTranslate(long native_object, float dx, float dy) {
+ /*package*/ static void native_preTranslate(long native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getTranslate(dx, dy));
}
-
- d.preTransform(getTranslate(dx, dy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preScale(long native_object, float sx, float sy,
+ /*package*/ static void native_preScale(long native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getScale(sx, sy, px, py));
}
-
- d.preTransform(getScale(sx, sy, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preScale(long native_object, float sx, float sy) {
+ /*package*/ static void native_preScale(long native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getScale(sx, sy));
}
-
- d.preTransform(getScale(sx, sy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preRotate(long native_object, float degrees,
+ /*package*/ static void native_preRotate(long native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getRotate(degrees, px, py));
}
-
- d.preTransform(getRotate(degrees, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preRotate(long native_object, float degrees) {
+ /*package*/ static void native_preRotate(long native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
- }
+ if (d != null) {
- double rad = Math.toRadians(degrees);
- float sin = (float)Math.sin(rad);
- float cos = (float)Math.cos(rad);
+ double rad = Math.toRadians(degrees);
+ float sin = (float) Math.sin(rad);
+ float cos = (float) Math.cos(rad);
- d.preTransform(getRotate(sin, cos));
- return true;
+ d.preTransform(getRotate(sin, cos));
+ }
}
@LayoutlibDelegate
- /*package*/ static boolean native_preSkew(long native_object, float kx, float ky,
+ /*package*/ static void native_preSkew(long native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getSkew(kx, ky, px, py));
}
-
- d.preTransform(getSkew(kx, ky, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preSkew(long native_object, float kx, float ky) {
+ /*package*/ static void native_preSkew(long native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getSkew(kx, ky));
}
-
- d.preTransform(getSkew(kx, ky));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preConcat(long native_object, long other_matrix) {
+ /*package*/ static void native_preConcat(long native_object, long other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
- }
-
Matrix_Delegate other = sManager.getDelegate(other_matrix);
- if (other == null) {
- return false;
+ if (d != null && other != null) {
+ d.preTransform(other.mValues);
}
-
- d.preTransform(other.mValues);
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postTranslate(long native_object, float dx, float dy) {
+ /*package*/ static void native_postTranslate(long native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getTranslate(dx, dy));
}
-
- d.postTransform(getTranslate(dx, dy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postScale(long native_object, float sx, float sy,
+ /*package*/ static void native_postScale(long native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getScale(sx, sy, px, py));
}
-
- d.postTransform(getScale(sx, sy, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postScale(long native_object, float sx, float sy) {
+ /*package*/ static void native_postScale(long native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getScale(sx, sy));
}
-
- d.postTransform(getScale(sx, sy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postRotate(long native_object, float degrees,
+ /*package*/ static void native_postRotate(long native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getRotate(degrees, px, py));
}
-
- d.postTransform(getRotate(degrees, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postRotate(long native_object, float degrees) {
+ /*package*/ static void native_postRotate(long native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getRotate(degrees));
}
-
- d.postTransform(getRotate(degrees));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postSkew(long native_object, float kx, float ky,
+ /*package*/ static void native_postSkew(long native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getSkew(kx, ky, px, py));
}
-
- d.postTransform(getSkew(kx, ky, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postSkew(long native_object, float kx, float ky) {
+ /*package*/ static void native_postSkew(long native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getSkew(kx, ky));
}
-
- d.postTransform(getSkew(kx, ky));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postConcat(long native_object, long other_matrix) {
+ /*package*/ static void native_postConcat(long native_object, long other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
- }
-
Matrix_Delegate other = sManager.getDelegate(other_matrix);
- if (other == null) {
- return false;
+ if (d != null && other != null) {
+ d.postTransform(other.mValues);
}
-
- d.postTransform(other.mValues);
- return true;
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 7007b71..83df745 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -420,7 +420,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+ /*package*/ static void native_setShadowLayer(long paint, float radius, float dx, float dy,
int color) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -428,6 +428,24 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static boolean native_hasShadowLayer(long paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.hasShadowLayer is not supported.", null, null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
+ // TODO
+ }
+
+ @LayoutlibDelegate
/*package*/ static float getTextSize(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -688,7 +706,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getStyle(long native_object) {
+ /*package*/ static int native_getStyle(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -710,7 +728,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getStrokeCap(long native_object) {
+ /*package*/ static int native_getStrokeCap(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -732,7 +750,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getStrokeJoin(long native_object) {
+ /*package*/ static int native_getStrokeJoin(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -889,7 +907,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getTextAlign(long native_object) {
+ /*package*/ static int native_getTextAlign(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -922,7 +940,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getTextWidths(long native_object, char[] text, int index,
+ /*package*/ static int native_getTextWidths(long native_object, char[] text, int index,
int count, int bidiFlags, float[] widths) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -964,14 +982,14 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getTextWidths(long native_object, String text, int start,
+ /*package*/ static int native_getTextWidths(long native_object, String text, int start,
int end, int bidiFlags, float[] widths) {
return native_getTextWidths(native_object, text.toCharArray(), start, end - start,
bidiFlags, widths);
}
@LayoutlibDelegate
- /* package */static long native_getTextGlyphs(long native_object, String text, int start,
+ /* package */static int native_getTextGlyphs(long native_object, String text, int start,
int end, int contextStart, int contextEnd, int flags, char[] glyphs) {
// FIXME
return 0;
@@ -1012,7 +1030,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getTextRunCursor(Paint thisPaint, long native_object, char[] text,
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1021,7 +1039,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getTextRunCursor(Paint thisPaint, long native_object, String text,
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, String text,
int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 6f6ef20..0ec7115 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -142,7 +142,14 @@ public final class Path_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long native_getFillType(long nPath) {
+ /*package*/ static boolean native_isConvex(long nPath) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.isConvex is not supported.", null, null);
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getFillType(long nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return 0;
@@ -311,16 +318,6 @@ public final class Path_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_addRect(long nPath, RectF rect, int dir) {
- Path_Delegate pathDelegate = sManager.getDelegate(nPath);
- if (pathDelegate == null) {
- return;
- }
-
- pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
- }
-
- @LayoutlibDelegate
/*package*/ static void native_addRect(long nPath,
float left, float top, float right, float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -332,14 +329,15 @@ public final class Path_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_addOval(long nPath, RectF oval, int dir) {
+ /*package*/ static void native_addOval(long nPath, float left, float top, float right,
+ float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
}
pathDelegate.mPath.append(new Ellipse2D.Float(
- oval.left, oval.top, oval.width(), oval.height()), false);
+ left, top, right - left, bottom - top), false);
}
@LayoutlibDelegate
@@ -484,6 +482,11 @@ public final class Path_Delegate {
sManager.removeJavaReferenceFor(nPath);
}
+ @LayoutlibDelegate
+ /*package*/ static float[] native_approximate(long nPath, float error) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.approximate() not supported", null);
+ return new float[0];
+ }
// ---- Private helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 6049919..1bc3033 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -60,12 +60,5 @@ public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
return sManager.addNewDelegate(newDelegate);
}
- @LayoutlibDelegate
- /*package*/ static long nCreatePorterDuffFilter(long nativeFilter, int srcColor,
- int porterDuffMode) {
- // pass
- return 0;
- }
-
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
index d2aae92..edb7025 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -289,7 +289,6 @@ public class Region_Delegate {
dstRegion.mArea.reset();
dstRegion.mArea.add(srcRegion.mArea);
- return;
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java
index ff82a5e..1e7564e 100644
--- a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,26 +23,29 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.util.Map;
/**
- * Delegate implementing the native methods of android.os.Build
+ * Delegate implementing the native methods of android.os.SystemProperties
*
- * Through the layoutlib_create tool, the original native methods of Build have been replaced
- * by calls to methods of the same name in this delegate class.
+ * Through the layoutlib_create tool, the original native methods of SystemProperties have been
+ * replaced by calls to methods of the same name in this delegate class.
*
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
* around to map int to instance of the delegate.
- *
*/
-public class Build_Delegate {
+public class SystemProperties_Delegate {
@LayoutlibDelegate
- /*package*/ static String getString(String property) {
+ /*package*/ static String native_get(String key) {
+ return native_get(key, "");
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String native_get(String key, String def) {
Map<String, String> properties = Bridge.getPlatformProperties();
- String value = properties.get(property);
+ String value = properties.get(key);
if (value != null) {
return value;
}
- return Build.UNKNOWN;
+ return def;
}
-
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index a2e93a7..af22f44 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -121,10 +121,11 @@ public final class BridgeInflater extends LayoutInflater {
}
@Override
- public View createViewFromTag(View parent, String name, AttributeSet attrs) {
+ public View createViewFromTag(View parent, String name, AttributeSet attrs,
+ boolean inheritContext) {
View view = null;
try {
- view = super.createViewFromTag(parent, name, attrs);
+ view = super.createViewFromTag(parent, name, attrs, inheritContext);
} catch (InflateException e) {
// try to load the class from using the custom view loader
try {
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index dd2cbc1..757cdd2 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -23,22 +23,13 @@ import com.android.internal.view.IInputMethodClient;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.IApplicationToken;
-import android.view.IInputFilter;
-import android.view.IOnKeyguardExitResult;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.IWindowSession;
-import java.util.List;
+import java.lang.Override;
/**
* Basic implementation of {@link IWindowManager} so that {@link Display} (and
@@ -458,44 +449,26 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public IBinder getFocusedWindowToken() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void setInputFilter(IInputFilter filter) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void getWindowFrame(IBinder token, Rect outFrame) {
+ public boolean isRotationFrozen() throws RemoteException {
// TODO Auto-generated method stub
+ return false;
}
@Override
- public void setMagnificationCallbacks(IMagnificationCallbacks callbacks) {
+ public void enableScreenIfNeeded() throws RemoteException {
// TODO Auto-generated method stub
}
@Override
- public void setMagnificationSpec(MagnificationSpec spec) {
+ public boolean clearWindowContentFrameStats(IBinder token) throws RemoteException {
// TODO Auto-generated method stub
+ return false;
}
@Override
- public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
+ public WindowContentFrameStats getWindowContentFrameStats(IBinder token)
+ throws RemoteException {
// TODO Auto-generated method stub
return null;
}
-
- @Override
- public boolean isRotationFrozen() throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void setTouchExplorationEnabled(boolean enabled) {
- }
}
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 3db3a1b..7a73fae 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -48,9 +48,9 @@ public class LayoutInflater_Delegate {
* This implementation just records the merge status before calling the default implementation.
*/
@LayoutlibDelegate
- /*package*/ static void rInflate(LayoutInflater thisInflater,
- XmlPullParser parser, View parent, final AttributeSet attrs,
- boolean finishInflate) throws XmlPullParserException, IOException {
+ /* package */ static void rInflate(LayoutInflater thisInflater, XmlPullParser parser,
+ View parent, final AttributeSet attrs, boolean finishInflate, boolean inheritContext)
+ throws XmlPullParserException, IOException {
if (finishInflate == false) {
// this is a merge rInflate!
@@ -61,7 +61,7 @@ public class LayoutInflater_Delegate {
// ---- START DEFAULT IMPLEMENTATION.
- thisInflater.rInflate_Original(parser, parent, attrs, finishInflate);
+ thisInflater.rInflate_Original(parser, parent, attrs, finishInflate, inheritContext);
// ---- END DEFAULT IMPLEMENTATION.
@@ -74,10 +74,8 @@ public class LayoutInflater_Delegate {
}
@LayoutlibDelegate
- public static void parseInclude(
- LayoutInflater thisInflater,
- XmlPullParser parser, View parent, AttributeSet attrs)
- throws XmlPullParserException, IOException {
+ public static void parseInclude(LayoutInflater thisInflater, XmlPullParser parser, View parent,
+ AttributeSet attrs, boolean inheritContext) throws XmlPullParserException, IOException {
int type;
@@ -113,9 +111,11 @@ public class LayoutInflater_Delegate {
if (TAG_MERGE.equals(childName)) {
// Inflate all children.
- thisInflater.rInflate(childParser, parent, childAttrs, false);
+ thisInflater.rInflate(childParser, parent, childAttrs, false,
+ inheritContext);
} else {
- final View view = thisInflater.createViewFromTag(parent, childName, childAttrs);
+ final View view = thisInflater.createViewFromTag(parent, childName,
+ childAttrs, inheritContext);
final ViewGroup group = (ViewGroup) parent;
// We try to load the layout params set in the <include /> tag. If
@@ -151,7 +151,7 @@ public class LayoutInflater_Delegate {
}
// Inflate all children.
- thisInflater.rInflate(childParser, view, childAttrs, true);
+ thisInflater.rInflate(childParser, view, childAttrs, true, true);
// Attempt to override the included layout's android:id with the
// one set on the <include /> tag itself.
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
index e34ad38..0dddf3d 100644
--- a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -23,7 +23,6 @@ import com.android.internal.view.menu.BridgeMenuItemImpl;
import com.android.internal.view.menu.MenuView;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.util.AttributeSet;
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilderAccessor.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilderAccessor.java
deleted file mode 100644
index f0798cb..0000000
--- a/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilderAccessor.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.android.internal.view.menu;
-
-import java.util.ArrayList;
-
-/**
- * To access non public members of {@link MenuBuilder}
- */
-public class MenuBuilderAccessor {
- public static ArrayList<MenuItemImpl> getNonActionItems(MenuBuilder builder) {
- return builder.getNonActionItems();
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java b/tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java
index 47a3679..40b6220 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import com.android.internal.view.menu.ActionMenuPresenter;
+import android.widget.ActionMenuPresenter;
/**
* To access non public members of AbsActionBarView
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index 01740b1..89288bf 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -135,6 +135,7 @@ public final class BridgeContentProvider implements IContentProvider {
return null;
}
+
@Override
public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 6595ce1..d31239b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -58,6 +58,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -101,6 +102,7 @@ public final class BridgeContext extends Context {
private final ApplicationInfo mApplicationInfo;
private final IProjectCallback mProjectCallback;
private final WindowManager mWindowManager;
+ private final DisplayManager mDisplayManager;
private Resources.Theme mTheme;
@@ -149,6 +151,7 @@ public final class BridgeContext extends Context {
}
mWindowManager = new WindowManagerImpl(mMetrics);
+ mDisplayManager = new DisplayManager(this);
}
/**
@@ -455,6 +458,10 @@ public final class BridgeContext extends Context {
return new PowerManager(this, new BridgePowerManager(), new Handler());
}
+ if (DISPLAY_SERVICE.equals(service)) {
+ return mDisplayManager;
+ }
+
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
@@ -560,7 +567,7 @@ public final class BridgeContext extends Context {
StyleResourceValue customStyleValues = null;
if (customStyle != null) {
ResourceValue item = mRenderResources.findResValue(customStyle,
- false /*forceFrameworkOnly*/);
+ isPlatformFile /*forceFrameworkOnly*/);
// resolve it in case it links to something else
item = mRenderResources.resolveResValue(item);
@@ -1277,6 +1284,14 @@ public final class BridgeContext extends Context {
}
@Override
+ public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+ Handler scheduler,
+ int initialCode, String initialData, Bundle initialExtras) {
+ // pass
+ }
+
+ @Override
public void sendStickyBroadcast(Intent arg0) {
// pass
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 3cf5ed5..0bb7fc2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -209,6 +209,17 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
}
@Override
+ public int getInputMethodWindowVisibleHeight() throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public void notifyTextCommitted() throws RemoteException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void updateStatusIcon(IBinder arg0, String arg1, int arg2) throws RemoteException {
// TODO Auto-generated method stub
@@ -227,4 +238,9 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public void setCursorAnchorMonitorMode(IBinder arg0, int arg1) {
+ // TODO Auto-generated method stub
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 95221fb..00c0f93 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -39,7 +39,7 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
- public void acquireWakeLock(IBinder arg0, int arg1, String arg2, String arg2_5, WorkSource arg3)
+ public void acquireWakeLock(IBinder arg0, int arg1, String arg2, String arg2_5, WorkSource arg3, String arg4)
throws RemoteException {
// pass for now.
}
@@ -51,6 +51,11 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
+ public void powerHint(int hintId, int data) {
+ // pass for now.
+ }
+
+ @Override
public void crash(String arg0) throws RemoteException {
// pass for now.
}
@@ -111,7 +116,7 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
- public void updateWakeLockWorkSource(IBinder arg0, WorkSource arg1) throws RemoteException {
+ public void updateWakeLockWorkSource(IBinder arg0, WorkSource arg1, String arg2) throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
index 0e39a57..936ab4f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -25,11 +25,9 @@ import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams;
import com.android.ide.common.rendering.api.SystemViewCookie;
import com.android.internal.R;
-import com.android.internal.app.ActionBarImpl;
+import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.util.Predicate;
-import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuBuilderAccessor;
import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.widget.ActionBarAccessor;
import com.android.internal.widget.ActionBarContainer;
@@ -52,6 +50,7 @@ import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ActionMenuView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
@@ -101,7 +100,7 @@ public class ActionBarLayout extends LinearLayout {
// Inflate action bar layout.
LayoutInflater.from(context).inflate(R.layout.screen_action_bar, this,
true /*attachToRoot*/);
- mActionBar = new ActionBarImpl(this);
+ mActionBar = new WindowDecorActionBar(this);
// Set contexts.
mBridgeContext = context;
@@ -323,7 +322,7 @@ public class ActionBarLayout extends LinearLayout {
return false;
}
// Copied from android.widget.ActionMenuPresenter.updateMenuView()
- ArrayList<MenuItemImpl> menus = MenuBuilderAccessor.getNonActionItems(mMenuBuilder);
+ ArrayList<MenuItemImpl> menus = mMenuBuilder.getNonActionItems();
if (ActionBarAccessor.getActionMenuPresenter(mActionBarView).isOverflowReserved() &&
menus != null) {
final int count = menus.size();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index bcd08eb4..86797e5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -87,7 +87,7 @@ abstract class CustomBar extends LinearLayout {
}
}
- private InputStream getIcon(String iconName, Density[] densityInOut, LayoutDirection direction,
+ private InputStream getIcon(String iconName, Density[] densityInOut, LayoutDirection direction,
String[] pathOut, boolean tryOtherDensities) {
// current density
Density density = densityInOut[0];
@@ -111,10 +111,10 @@ abstract class CustomBar extends LinearLayout {
return stream;
}
}
- }
- // couldn't find resource with direction qualifier. try without.
- if (direction != null) {
- return getIcon(iconName, densityInOut, null, pathOut, true);
+ // couldn't find resource with direction qualifier. try without.
+ if (direction != null) {
+ return getIcon(iconName, densityInOut, null, pathOut, true);
+ }
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 84e676e..112c267 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -17,7 +17,6 @@
package com.android.layoutlib.bridge.bars;
import com.android.resources.Density;
-import com.android.layoutlib.bridge.Bridge;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java
index 79e231c..778305d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java
@@ -17,7 +17,6 @@
package com.android.layoutlib.bridge.bars;
import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuBuilderAccessor;
import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.view.menu.MenuView;
@@ -47,7 +46,7 @@ public class OverflowMenuAdapter extends BaseAdapter {
@Override
public int getCount() {
- ArrayList<MenuItemImpl> items = MenuBuilderAccessor.getNonActionItems(mMenu);
+ ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
if (mExpandedIndex < 0) {
return items.size();
}
@@ -56,7 +55,7 @@ public class OverflowMenuAdapter extends BaseAdapter {
@Override
public MenuItemImpl getItem(int position) {
- ArrayList<MenuItemImpl> items = MenuBuilderAccessor.getNonActionItems(mMenu);
+ ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
position++;
}
@@ -86,7 +85,7 @@ public class OverflowMenuAdapter extends BaseAdapter {
private void findExpandedIndex() {
final MenuItemImpl expandedItem = mMenu.getExpandedItem();
if (expandedItem != null) {
- final ArrayList<MenuItemImpl> items = MenuBuilderAccessor.getNonActionItems(mMenu);
+ final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
final int count = items.size();
for (int i = 0; i < count; i++) {
final MenuItemImpl item = items.get(i);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 3692d96..1498044 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -33,7 +33,6 @@ public class StatusBar extends CustomBar {
public StatusBar(Context context, Density density, int direction, boolean RtlEnabled)
throws XmlPullParserException {
// FIXME: if direction is RTL but it's not enabled in application manifest, mirror this bar.
-
super(context, density, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml");
// FIXME: use FILL_H?
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
index 53e1640..a2a8aa9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
@@ -18,6 +18,7 @@ package com.android.layoutlib.bridge.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
import android.util.SparseArray;
@@ -59,10 +60,8 @@ public class SparseWeakArray<E> {
* number of mappings.
*/
public SparseWeakArray(int initialCapacity) {
- initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
-
- mKeys = new long[initialCapacity];
- mValues = new WeakReference[initialCapacity];
+ mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+ mValues = new WeakReference[mKeys.length];
mSize = 0;
}
@@ -142,18 +141,6 @@ public class SparseWeakArray<E> {
mGarbage = false;
mSize = o;
-
- int newSize = ArrayUtils.idealLongArraySize(mSize);
- if (newSize < mKeys.length) {
- long[] nkeys = new long[newSize];
- WeakReference<?>[] nvalues = new WeakReference[newSize];
-
- System.arraycopy(mKeys, 0, nkeys, 0, newSize);
- System.arraycopy(mValues, 0, nvalues, 0, newSize);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
}
/**
@@ -182,28 +169,8 @@ public class SparseWeakArray<E> {
i = ~binarySearch(mKeys, 0, mSize, key);
}
- if (mSize >= mKeys.length) {
- int n = ArrayUtils.idealLongArraySize(mSize + 1);
-
- long[] nkeys = new long[n];
- WeakReference<?>[] nvalues = new WeakReference[n];
-
- // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- if (mSize - i != 0) {
- // Log.e("SparseArray", "move " + (mSize - i));
- System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
- System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
- }
-
- mKeys[i] = key;
- mValues[i] = new WeakReference(value);
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mValues = GrowingArrayUtils.insert(mValues, mSize, i, new WeakReference(value));
mSize++;
}
}
@@ -321,24 +288,9 @@ public class SparseWeakArray<E> {
gc();
}
- int pos = mSize;
- if (pos >= mKeys.length) {
- int n = ArrayUtils.idealLongArraySize(pos + 1);
-
- long[] nkeys = new long[n];
- WeakReference<?>[] nvalues = new WeakReference[n];
-
- // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- mKeys[pos] = key;
- mValues[pos] = new WeakReference(value);
- mSize = pos + 1;
+ mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+ mValues = GrowingArrayUtils.append(mValues, mSize, new WeakReference(value));
+ mSize++;
}
private boolean hasReclaimedRefs() {
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 0f66fd7..19d249b 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -18,6 +18,7 @@ package libcore.icu;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import com.ibm.icu.text.DateTimePatternGenerator;
+import com.ibm.icu.util.Currency;
import com.ibm.icu.util.ULocale;
import java.util.Locale;
@@ -117,6 +118,11 @@ public class ICU_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static int getCurrencyNumericCode(String currencyCode) {
+ return Currency.getInstance(currencyCode).getNumericCode();
+ }
+
+ @LayoutlibDelegate
/*package*/ static String getCurrencySymbol(String locale, String currencyCode) {
return "";
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
index 7c0bc84..274516c 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
@@ -121,14 +121,6 @@ public class TestDelegates extends TestCase {
Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(),
parameters);
- // check that the method has the annotation
- assertNotNull(
- String.format(
- "Delegate method %1$s for class %2$s does not have the @LayoutlibDelegate annotation",
- delegateMethod.getName(),
- originalClass.getName()),
- delegateMethod.getAnnotation(LayoutlibDelegate.class));
-
// check the return type of the methods match.
assertTrue(
String.format("Delegate method %1$s.%2$s does not match the corresponding " +
@@ -138,6 +130,14 @@ public class TestDelegates extends TestCase {
originalMethod.getReturnType().getName()),
delegateMethod.getReturnType() == originalMethod.getReturnType());
+ // check that the method has the annotation
+ assertNotNull(
+ String.format(
+ "Delegate method %1$s for class %2$s does not have the @LayoutlibDelegate annotation",
+ delegateMethod.getName(),
+ originalClass.getName()),
+ delegateMethod.getAnnotation(LayoutlibDelegate.class));
+
// check that the method is static
assertTrue(
String.format(
diff --git a/tools/layoutlib/create/.classpath b/tools/layoutlib/create/.classpath
index cd8bb0d..25c3b3e 100644
--- a/tools/layoutlib/create/.classpath
+++ b/tools/layoutlib/create/.classpath
@@ -4,6 +4,6 @@
<classpathentry excluding="mock_data/" kind="src" path="tests"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/asm-tools/asm-4.0.jar" sourcepath="/ANDROID_PLAT/prebuilts/tools/common/asm-tools/src-4.0.zip"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/asm/asm-4.0.jar" sourcepath="/ANDROID_PLAT_SRC/prebuilts/misc/common/asm/src.zip"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt
index ef2b185..6e0a300 100644
--- a/tools/layoutlib/create/README.txt
+++ b/tools/layoutlib/create/README.txt
@@ -4,46 +4,45 @@
- Description -
---------------
-Layoutlib_create generates a JAR library used by the Eclipse graphical layout editor
-to perform layout.
+Layoutlib_create generates a JAR library used by the Eclipse graphical layout editor to perform
+layout.
- Usage -
---------
- ./layoutlib_create path/to/android.jar destination.jar
+ ./layoutlib_create destination.jar path/to/android1.jar path/to/android2.jar
- Design Overview -
-------------------
-Layoutlib_create uses the "android.jar" containing all the Java code used by Android
-as generated by the Android build, right before the classes are converted to a DEX format.
+Layoutlib_create uses a few jars from the framework containing the Java code used by Android as
+generated by the Android build, right before the classes are converted to a DEX format.
-The Android JAR can't be used directly in Eclipse:
-- it contains references to native code (which we want to avoid in Eclipse),
-- some classes need to be overridden, for example all the drawing code that is
- replaced by Java 2D calls in Eclipse.
-- some of the classes that need to be changed are final and/or we need access
- to their private internal state.
+These jars can't be used directly in Eclipse as:
+- they contains references to native code (which we want to avoid in Eclipse),
+- some classes need to be overridden, for example all the drawing code that is replaced by Java 2D
+ calls in Eclipse.
+- some of the classes that need to be changed are final and/or we need access to their private
+ internal state.
Consequently this tool:
- parses the input JAR,
- modifies some of the classes directly using some bytecode manipulation,
- filters some packages and removes those we don't want in the output JAR,
- injects some new classes,
-- generates a modified JAR file that is suitable for the Android plugin
- for Eclipse to perform rendering.
+- generates a modified JAR file that is suitable for the Android plugin for Eclipse to perform
+ rendering.
The ASM library is used to do the bytecode modification using its visitor pattern API.
-The layoutlib_create is *NOT* generic. There is no configuration file. Instead all the
-configuration is done in the main() method and the CreateInfo structure is expected to
-change with the Android platform as new classes are added, changed or removed.
+The layoutlib_create is *NOT* generic. There is no configuration file. Instead all the configuration
+is done in the main() method and the CreateInfo structure is expected to change with the Android
+platform as new classes are added, changed or removed.
-The resulting JAR is used by layoutlib_bridge (a.k.a. "the bridge"), also part of the
-platform, that provides all the necessary missing implementation for rendering graphics
-in Eclipse.
+The resulting JAR is used by layoutlib_bridge (a.k.a. "the bridge"), also part of the platform, that
+provides all the necessary missing implementation for rendering graphics in Eclipse.
@@ -58,97 +57,96 @@ The tool works in two phases:
- Analyzer
----------
-The goal of the analyzer is to create a graph of all the classes from the input JAR
-with their dependencies and then only keep the ones we want.
+The goal of the analyzer is to create a graph of all the classes from the input JAR with their
+dependencies and then only keep the ones we want.
-To do that, the analyzer is created with a list of base classes to keep -- everything
-that derives from these is kept. Currently the one such class is android.view.View:
-since we want to render layouts, anything that is sort of a view needs to be kept.
+To do that, the analyzer is created with a list of base classes to keep -- everything that derives
+from these is kept. Currently the one such class is android.view.View: since we want to render
+layouts, anything that is sort of a view needs to be kept.
-The analyzer is also given a list of class names to keep in the output.
-This is done using shell-like glob patterns that filter on the fully-qualified
-class names, for example "android.*.R**" ("*" does not matches dots whilst "**" does,
-and "." and "$" are interpreted as-is).
-In practice we almost but not quite request the inclusion of full packages.
+The analyzer is also given a list of class names to keep in the output. This is done using
+shell-like glob patterns that filter on the fully-qualified class names, for example "android.*.R**"
+("*" does not matches dots whilst "**" does, and "." and "$" are interpreted as-is). In practice we
+almost but not quite request the inclusion of full packages.
-The analyzer is also given a list of classes to exclude. A fake implementation of these
-classes is injected by the Generator.
+The analyzer is also given a list of classes to exclude. A fake implementation of these classes is
+injected by the Generator.
-With this information, the analyzer parses the input zip to find all the classes.
-All classes deriving from the requested bases classes are kept.
-All classes which name matched the glob pattern are kept.
-The analysis then finds all the dependencies of the classes that are to be kept
-using an ASM visitor on the class, the field types, the method types and annotations types.
-Classes that belong to the current JRE are excluded.
+With this information, the analyzer parses the input zip to find all the classes. All classes
+deriving from the requested bases classes are kept. All classes whose name match the glob pattern
+are kept. The analysis then finds all the dependencies of the classes that are to be kept using an
+ASM visitor on the class, the field types, the method types and annotations types. Classes that
+belong to the current JRE are excluded.
-The output of the analyzer is a set of ASM ClassReader instances which are then
-fed to the generator.
+The output of the analyzer is a set of ASM ClassReader instances which are then fed to the
+generator.
- Generator
-----------
-The generator is constructed from a CreateInfo struct that acts as a config file
-and lists:
-- the classes to inject in the output JAR -- these classes are directly implemented
- in layoutlib_create and will be used to interface with the renderer in Eclipse.
+The generator is constructed from a CreateInfo struct that acts as a config file and lists:
+- the classes to inject in the output JAR -- these classes are directly implemented in
+ layoutlib_create and will be used to interface with the renderer in Eclipse.
- specific methods to override (see method stubs details below).
- specific methods for which to delegate calls.
- specific methods to remove based on their return type.
- specific classes to rename.
- specific classes to refactor.
-Each of these are specific strategies we use to be able to modify the Android code
-to fit within the Eclipse renderer. These strategies are explained beow.
+Each of these are specific strategies we use to be able to modify the Android code to fit within the
+Eclipse renderer. These strategies are explained beow.
-The core method of the generator is transform(): it takes an input ASM ClassReader
-and modifies it to produce a byte array suitable for the final JAR file.
+The core method of the generator is transform(): it takes an input ASM ClassReader and modifies it
+to produce a byte array suitable for the final JAR file.
The first step of the transformation is to implement the method delegates.
-The TransformClassAdapter is then used to process the potentially renamed class.
-All protected or private classes are market as public.
-All classes are made non-final.
-Interfaces are left as-is.
+The TransformClassAdapter is then used to process the potentially renamed class. All protected or
+private classes are market as public. All classes are made non-final. Interfaces are left as-is.
-If a method has a return type that must be erased, the whole method is skipped.
-Methods are also changed from protected/private to public.
-The code of the methods is then kept as-is, except for native methods which are
-replaced by a stub. Methods that are to be overridden are also replaced by a stub.
+If a method has a return type that must be erased, the whole method is skipped. Methods are also
+changed from protected/private to public. The code of the methods is then kept as-is, except for
+native methods which are replaced by a stub. Methods that are to be overridden are also replaced by
+a stub.
Finally fields are also visited and changed from protected/private to public.
-The next step of the transformation is changing the name of the class in case
-we requested the class to be renamed. This uses the RenameClassAdapter to also rename
-all inner classes and references in methods and types. Note that other classes are
-not transformed and keep referencing the original name.
-
-The class is then fed to RefactorClassAdapter which is like RenameClassAdapter but
-updates the references in all classes. This is used to update the references of classes
-in the java package that were added in the Dalvik VM but are not a part of the standard
-JVM. The existing classes are modified to update all references to these non-standard
-classes. An alternate implementation of these (com.android.tools.layoutlib.java.*) is
-injected.
-
-The ClassAdapters are chained together to achieve the desired output. (Look at section
-2.2.7 Transformation chains in the asm user guide, link in the References.) The order of
-execution of these is:
+The next step of the transformation is changing the name of the class in case we requested the class
+to be renamed. This uses the RenameClassAdapter to also rename all inner classes and references in
+methods and types. Note that other classes are not transformed and keep referencing the original
+name.
+
+The class is then fed to RefactorClassAdapter which is like RenameClassAdapter but updates the
+references in all classes. This is used to update the references of classes in the java package that
+were added in the Dalvik VM but are not a part of the standard JVM. The existing classes are
+modified to update all references to these non-standard classes. An alternate implementation of
+these (com.android.tools.layoutlib.java.*) is injected.
+
+RenameClassAdapter and RefactorClassAdapter both inherit from AbstractClassAdapter which changes the
+class version (version of the JDK used to compile the class) to 50 (corresponding to Java 6), if the
+class was originally compiled with Java 7 (version 51). This is because we don't currently generate
+the StackMapTable correctly and Java 7 VM enforces that classes with version greater than 51 have
+valid StackMapTable. As a side benefit of this, we can continue to support Java 6 because Java 7 on
+Mac has horrible font rendering support.
+
+The ClassAdapters are chained together to achieve the desired output. (Look at section 2.2.7
+Transformation chains in the asm user guide, link in the References.) The order of execution of
+these is:
ClassReader -> [DelegateClassAdapter] -> TransformClassAdapter -> [RenameClassAdapter] ->
RefactorClassAdapter -> ClassWriter
- Method stubs
--------------
-As indicated above, all native and overridden methods are replaced by a stub.
-We don't have the code to replace with in layoutlib_create.
-Instead the StubMethodAdapter replaces the code of the method by a call to
-OverrideMethod.invokeX(). When using the final JAR, the bridge can register
+As indicated above, all native and overridden methods are replaced by a stub. We don't have the
+code to replace with in layoutlib_create. Instead the StubMethodAdapter replaces the code of the
+method by a call to OverrideMethod.invokeX(). When using the final JAR, the bridge can register
listeners from these overridden method calls based on the method signatures.
-The listeners are currently pretty basic: we only pass the signature of the
-method being called, its caller object and a flag indicating whether the
-method was native. We do not currently provide the parameters. The listener
-can however specify the return value of the overridden method.
+The listeners are currently pretty basic: we only pass the signature of the method being called, its
+caller object and a flag indicating whether the method was native. We do not currently provide the
+parameters. The listener can however specify the return value of the overridden method.
This strategy is now obsolete and replaced by the method delegates.
@@ -156,97 +154,89 @@ This strategy is now obsolete and replaced by the method delegates.
- Strategies
------------
-We currently have 6 strategies to deal with overriding the rendering code
-and make it run in Eclipse. Most of these strategies are implemented hand-in-hand
-by the bridge (which runs in Eclipse) and the generator.
+We currently have 6 strategies to deal with overriding the rendering code and make it run in
+Eclipse. Most of these strategies are implemented hand-in-hand by the bridge (which runs in Eclipse)
+and the generator.
1- Class Injection
This is the easiest: we currently inject the following classes:
-- OverrideMethod and its associated MethodListener and MethodAdapter are used
- to intercept calls to some specific methods that are stubbed out and change
- their return value.
-- CreateInfo class, which configured the generator. Not used yet, but could
- in theory help us track what the generator changed.
-- AutoCloseable and Objects are part of Java 7. To enable us to still run on Java 6, new
- classes are injected. The implementation for these classes has been taken from
- Android's libcore (platform/libcore/luni/src/main/java/java/...).
-- Charsets, IntegralToString and UnsafeByteSequence are not part of the standard JAVA VM.
- They are added to the Dalvik VM for performance reasons. An implementation that is very
- close to the original (which is at platform/libcore/luni/src/main/java/...) is injected.
- Since these classees were in part of the java package, where we can't inject classes,
- all references to these have been updated (See strategy 4- Refactoring Classes).
+- OverrideMethod and its associated MethodListener and MethodAdapter are used to intercept calls to
+ some specific methods that are stubbed out and change their return value.
+- CreateInfo class, which configured the generator. Not used yet, but could in theory help us track
+ what the generator changed.
+- AutoCloseable and Objects are part of Java 7. To enable us to still run on Java 6, new classes are
+ injected. The implementation for these classes has been taken from Android's libcore
+ (platform/libcore/luni/src/main/java/java/...).
+- Charsets, IntegralToString and UnsafeByteSequence are not part of the standard JAVA VM. They are
+ added to the Dalvik VM for performance reasons. An implementation that is very close to the
+ original (which is at platform/libcore/luni/src/main/java/...) is injected. Since these classees
+ were in part of the java package, where we can't inject classes, all references to these have been
+ updated (See strategy 4- Refactoring Classes).
2- Overriding methods
-As explained earlier, the creator doesn't have any replacement code for
-methods to override. Instead it removes the original code and replaces it
-by a call to a specific OveriddeMethod.invokeX(). The bridge then registers
-a listener on the method signature and can provide an implementation.
+As explained earlier, the creator doesn't have any replacement code for methods to override. Instead
+it removes the original code and replaces it by a call to a specific OveriddeMethod.invokeX(). The
+bridge then registers a listener on the method signature and can provide an implementation.
-This strategy is now obsolete and replaced by the method delegates.
-See strategy 5 below.
+This strategy is now obsolete and replaced by the method delegates (See strategy 6- Method
+Delegates).
3- Renaming classes
-This simply changes the name of a class in its definition, as well as all its
-references in internal inner classes and methods.
-Calls from other classes are not modified -- they keep referencing the original
-class name. This allows the bridge to literally replace an implementation.
+This simply changes the name of a class in its definition, as well as all its references in internal
+inner classes and methods. Calls from other classes are not modified -- they keep referencing the
+original class name. This allows the bridge to literally replace an implementation.
-An example will make this easier: android.graphics.Paint is the main drawing
-class that we need to replace. To do so, the generator renames Paint to _original_Paint.
-Later the bridge provides its own replacement version of Paint which will be used
-by the rest of the Android stack. The replacement version of Paint can still use
-(either by inheritance or delegation) all the original non-native code of _original_Paint
-if it so desires.
+An example will make this easier: android.graphics.Paint is the main drawing class that we need to
+replace. To do so, the generator renames Paint to _original_Paint. Later the bridge provides its own
+replacement version of Paint which will be used by the rest of the Android stack. The replacement
+version of Paint can still use (either by inheritance or delegation) all the original non-native
+code of _original_Paint if it so desires.
-Some of the Android classes are basically wrappers over native objects and since
-we don't have the native code in Eclipse, we need to provide a full alternate
-implementation. Sub-classing doesn't work as some native methods are static and
-we don't control object creation.
+Some of the Android classes are basically wrappers over native objects and since we don't have the
+native code in Eclipse, we need to provide a full alternate implementation. Sub-classing doesn't
+work as some native methods are static and we don't control object creation.
This won't rename/replace the inner static methods of a given class.
4- Refactoring classes
-This is very similar to the Renaming classes except that it also updates the reference in
-all classes. This is done for classes which are added to the Dalvik VM for performance
-reasons but are not present in the Standard Java VM. An implementation for these classes
-is also injected.
+This is very similar to the Renaming classes except that it also updates the reference in all
+classes. This is done for classes which are added to the Dalvik VM for performance reasons but are
+not present in the Standard Java VM. An implementation for these classes is also injected.
5- Method erasure based on return type
-This is mostly an implementation detail of the bridge: in the Paint class
-mentioned above, some inner static classes are used to pass around
-attributes (e.g. FontMetrics, or the Style enum) and all the original implementation
-is native.
+This is mostly an implementation detail of the bridge: in the Paint class mentioned above, some
+inner static classes are used to pass around attributes (e.g. FontMetrics, or the Style enum) and
+all the original implementation is native.
-In this case we have a strategy that tells the generator that anything returning, for
-example, the inner class Paint$Style in the Paint class should be discarded and the
-bridge will provide its own implementation.
+In this case we have a strategy that tells the generator that anything returning, for example, the
+inner class Paint$Style in the Paint class should be discarded and the bridge will provide its own
+implementation.
6- Method Delegates
-This strategy is used to override method implementations.
-Given a method SomeClass.MethodName(), 1 or 2 methods are generated:
-a- A copy of the original method named SomeClass.MethodName_Original().
- The content is the original method as-is from the reader.
- This step is omitted if the method is native, since it has no Java implementation.
-b- A brand new implementation of SomeClass.MethodName() which calls to a
- non-existing static method named SomeClass_Delegate.MethodName().
- The implementation of this 'delegate' method is done in layoutlib_brigde.
-
-The delegate method is a static method.
-If the original method is non-static, the delegate method receives the original 'this'
-as its first argument. If the original method is an inner non-static method, it also
-receives the inner 'this' as the second argument.
+This strategy is used to override method implementations. Given a method SomeClass.MethodName(), 1
+or 2 methods are generated:
+a- A copy of the original method named SomeClass.MethodName_Original(). The content is the original
+method as-is from the reader. This step is omitted if the method is native, since it has no Java
+implementation.
+b- A brand new implementation of SomeClass.MethodName() which calls to a non-existing static method
+named SomeClass_Delegate.MethodName(). The implementation of this 'delegate' method is done in
+layoutlib_brigde.
+
+The delegate method is a static method. If the original method is non-static, the delegate method
+receives the original 'this' as its first argument. If the original method is an inner non-static
+method, it also receives the inner 'this' as the second argument.
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
index b2caa25..323a791 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
@@ -177,6 +177,17 @@ public abstract class AbstractClassAdapter extends ClassVisitor {
}
}
+ /* Java 7 verifies the StackMapTable of a class if its version number is greater than 50.0.
+ * However, the check is disabled if the class version number is 50.0 or less. Generation
+ * of the StackMapTable requires a rewrite using the tree API of ASM. As a workaround,
+ * we rewrite the version number of the class to be 50.0
+ *
+ * http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6693236
+ */
+ if (version > 50) {
+ version = 50;
+ }
+
super.visit(version, access, name, signature, superName, interfaces);
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 911df7d..bb72a1e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -125,6 +125,7 @@ public final class CreateInfo implements ICreateInfo {
"android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
"android.content.res.Resources$Theme#obtainStyledAttributes",
"android.content.res.Resources$Theme#resolveAttribute",
+ "android.content.res.Resources#localeToLanguageTag",
"android.content.res.AssetManager#newTheme",
"android.content.res.AssetManager#deleteTheme",
"android.content.res.AssetManager#applyThemeStyle",
@@ -132,7 +133,6 @@ public final class CreateInfo implements ICreateInfo {
"android.graphics.BitmapFactory#finishDecode",
"android.os.Handler#sendMessageAtTime",
"android.os.HandlerThread#run",
- "android.os.Build#getString",
"android.text.format.DateFormat#is24HourFormat",
"android.view.Choreographer#getRefreshRate",
"android.view.Display#updateDisplayInfoLocked",
@@ -147,6 +147,7 @@ public final class CreateInfo implements ICreateInfo {
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
"com.android.internal.util.XmlUtils#convertValueToInt",
"com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
+ "android.os.SystemProperties#native_get",
};
/**
diff --git a/tools/layoutlib/rename_font/README b/tools/layoutlib/rename_font/README
new file mode 100644
index 0000000..600b756
--- /dev/null
+++ b/tools/layoutlib/rename_font/README
@@ -0,0 +1,9 @@
+This tool is used to rename the PS name encoded inside the ttf font that we ship
+with the SDK. There is bug in Java that returns incorrect results for
+java.awt.Font#layoutGlyphVector() if two fonts with same name but differnt
+versions are loaded. As a workaround, we rename all the fonts that we ship with
+the SDK by appending the font version to its name.
+
+
+The build_font.py copies all files from input_dir to output_dir while renaming
+the font files (*.ttf) in the process.
diff --git a/tools/layoutlib/rename_font/Roboto-Regular.ttf b/tools/layoutlib/rename_font/Roboto-Regular.ttf
new file mode 100644
index 0000000..7469063
--- /dev/null
+++ b/tools/layoutlib/rename_font/Roboto-Regular.ttf
Binary files differ
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
new file mode 100755
index 0000000..ea3dccc
--- /dev/null
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Rename the PS name of all fonts in the input directory and copy them to the
+output directory.
+
+Usage: build_font.py /path/to/input_fonts/ /path/to/output_fonts/
+
+"""
+
+import sys
+# fontTools is available at platform/external/fonttools
+from fontTools import ttx
+import re
+import os
+from lxml import etree
+import shutil
+import glob
+
+def main(argv):
+ if len(argv) != 2:
+ print "Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/"
+ sys.exit(1)
+ if not os.path.isdir(argv[0]):
+ print argv[0] + "is not a valid directory"
+ sys.exit(1)
+ if not os.path.isdir(argv[1]):
+ print argv[1] + "is not a valid directory"
+ sys.exit(1)
+ cwd = os.getcwd()
+ os.chdir(argv[1])
+ files = glob.glob('*')
+ for filename in files:
+ os.remove(filename)
+ os.chdir(cwd)
+ for filename in os.listdir(argv[0]):
+ if not os.path.splitext(filename)[1].lower() == ".ttf":
+ shutil.copy(os.path.join(argv[0], filename), argv[1])
+ continue
+ print os.path.join(argv[0], filename)
+ old_ttf_path = os.path.join(argv[0], filename)
+ # run ttx to generate an xml file in the output folder which represents all
+ # its info
+ ttx_args = ["-d", argv[1], old_ttf_path]
+ ttx.main(ttx_args)
+ # the path to the output file. The file name is the fontfilename.ttx
+ ttx_path = os.path.join(argv[1], filename)
+ ttx_path = ttx_path[:-1] + "x"
+ # now parse the xml file to change its PS name.
+ tree = etree.parse(ttx_path)
+ encoding = tree.docinfo.encoding
+ root = tree.getroot()
+ for name in root.iter('name'):
+ [old_ps_name, version] = get_font_info(name)
+ new_ps_name = old_ps_name + version
+ update_name(name, new_ps_name)
+ tree.write(ttx_path, xml_declaration=True, encoding=encoding )
+ # generate the udpated font now.
+ ttx_args = ["-d", argv[1], ttx_path]
+ ttx.main(ttx_args)
+ # delete the temp ttx file.
+ os.remove(ttx_path)
+
+def get_font_info(tag):
+ ps_name = None
+ ps_version = None
+ for namerecord in tag.iter('namerecord'):
+ if 'nameID' in namerecord.attrib:
+ # if the tag has nameID=6, it is the postscript name of the font.
+ # see: http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
+ if namerecord.attrib['nameID'] == '6':
+ if ps_name is not None:
+ if not sanitize(namerecord.text) == ps_name:
+ sys.exit('found multiple possibilities of the font name')
+ else:
+ ps_name = sanitize(namerecord.text)
+ # nameID=5 means the font version
+ if namerecord.attrib['nameID'] == '5':
+ if ps_version is not None:
+ if not ps_version == get_version(namerecord.text):
+ sys.exit('found multiple possibilities of the font version')
+ else:
+ ps_version = get_version(namerecord.text)
+ if ps_name is not None and ps_version is not None:
+ return [ps_name, ps_version]
+ sys.exit('didn\'t find the font name or version')
+
+
+def update_name(tag, name):
+ for namerecord in tag.iter('namerecord'):
+ if 'nameID' in namerecord.attrib:
+ if namerecord.attrib['nameID'] == '6':
+ namerecord.text = name
+
+def sanitize(string):
+ return re.sub(r'[^\w-]+', '', string)
+
+def get_version(string):
+ # The string must begin with "Version n.nn "
+ # to extract n.nn, we return the second entry in the split strings.
+ string = string.strip()
+ if not string.startswith("Version "):
+ sys.exit('mal-formed font version')
+ return sanitize(string.split()[1])
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
new file mode 100755
index 0000000..d4c86cb
--- /dev/null
+++ b/tools/layoutlib/rename_font/test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+"""Tests build_font.py by renaming a font.
+
+The test copies Roboto-Regular.ttf to a tmp directory and ask build_font.py to rename it and put in another dir.
+We then use ttx to dump the new font to its xml and check if rename was successful
+
+To test locally, use:
+PYTHONPATH="$PYTHONPATH:/path/to/android/checkout/external/fonttools/Lib" ./test.py
+"""
+
+import unittest
+import build_font
+
+from fontTools import ttx
+import os
+from lxml import etree
+import shutil
+import tempfile
+
+class MyTest(unittest.TestCase):
+ def test(self):
+ font_name = "Roboto-Regular.ttf"
+ srcdir = tempfile.mkdtemp()
+ print "srcdir: " + srcdir
+ shutil.copy(font_name, srcdir)
+ destdir = tempfile.mkdtemp()
+ print "destdir: " + destdir
+ self.assertTrue(build_font.main([srcdir, destdir]) is None)
+ out_path = os.path.join(destdir, font_name)
+ ttx.main([out_path])
+ ttx_path = out_path[:-1] + "x"
+ tree = etree.parse(ttx_path)
+ root = tree.getroot()
+ name_tag = root.find('name')
+ [f_name, f_version] = build_font.get_font_info(name_tag)
+ shutil.rmtree(srcdir)
+ shutil.rmtree(destdir)
+ self.assertEqual(f_name, "Roboto-Regular1200310")
+
+
+
+if __name__ == '__main__':
+ unittest.main()