summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt/AaptAssets.cpp14
-rw-r--r--tools/aapt/Android.mk9
-rw-r--r--tools/aapt/Command.cpp16
-rw-r--r--tools/aapt/CrunchCache.cpp2
-rw-r--r--tools/aapt/Images.cpp271
-rw-r--r--tools/aapt/Main.cpp2
-rw-r--r--tools/aapt/Package.cpp1
-rw-r--r--tools/aapt/Resource.cpp115
-rw-r--r--tools/aapt/ResourceTable.cpp338
-rw-r--r--tools/aapt/ResourceTable.h12
-rw-r--r--tools/aapt/StringPool.cpp82
-rw-r--r--tools/aapt/StringPool.h9
-rw-r--r--tools/aapt/XMLNode.cpp149
-rw-r--r--tools/aapt/ZipEntry.cpp93
-rw-r--r--tools/aapt/ZipEntry.h2
-rw-r--r--tools/aapt/ZipFile.cpp2
-rw-r--r--tools/aapt/qsort_r_compat.c90
-rw-r--r--tools/aapt/qsort_r_compat.h39
-rw-r--r--tools/aapt/tests/AaptConfig_test.cpp6
-rw-r--r--tools/aidl/aidl.cpp3
-rw-r--r--tools/apilint/apilint.py657
-rw-r--r--tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml2
-rw-r--r--tools/layoutlib/.idea/misc.xml28
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java20
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BlendComposite.java25
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java9
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java52
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java193
-rw-r--r--tools/layoutlib/bridge/src/android/text/LineBreaker.java42
-rw-r--r--tools/layoutlib/bridge/src/android/text/LineWidth.java35
-rw-r--r--tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java262
-rw-r--r--tools/layoutlib/bridge/src/android/text/Primitive.java92
-rw-r--r--tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java137
-rw-r--r--tools/layoutlib/bridge/src/android/text/TabStops.java44
-rw-r--r--tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java132
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java32
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java8
-rw-r--r--tools/layoutlib/bridge/src/android/view/ShadowPainter.java3
-rw-r--r--tools/layoutlib/bridge/src/android/view/WindowCallback.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java72
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java3
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java86
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java11
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java)18
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java219
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java19
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java62
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java46
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java75
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java2
-rw-r--r--tools/obbtool/Android.mk5
-rw-r--r--tools/obbtool/Main.cpp4
55 files changed, 2504 insertions, 1160 deletions
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index b7f64f63fdbc..871e04f7aa9d 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -15,7 +15,6 @@
#include <dirent.h>
#include <errno.h>
-static const char* kDefaultLocale = "default";
static const char* kAssetDir = "assets";
static const char* kResourceDir = "res";
static const char* kValuesDir = "values";
@@ -176,7 +175,7 @@ inline bool isNumber(const String8& string) {
void AaptLocaleValue::setLanguage(const char* languageChars) {
size_t i = 0;
- while ((*languageChars) != '\0') {
+ while ((*languageChars) != '\0' && i < sizeof(language)/sizeof(language[0])) {
language[i++] = tolower(*languageChars);
languageChars++;
}
@@ -184,7 +183,7 @@ void AaptLocaleValue::setLanguage(const char* languageChars) {
void AaptLocaleValue::setRegion(const char* regionChars) {
size_t i = 0;
- while ((*regionChars) != '\0') {
+ while ((*regionChars) != '\0' && i < sizeof(region)/sizeof(region[0])) {
region[i++] = toupper(*regionChars);
regionChars++;
}
@@ -192,7 +191,7 @@ void AaptLocaleValue::setRegion(const char* regionChars) {
void AaptLocaleValue::setScript(const char* scriptChars) {
size_t i = 0;
- while ((*scriptChars) != '\0') {
+ while ((*scriptChars) != '\0' && i < sizeof(script)/sizeof(script[0])) {
if (i == 0) {
script[i++] = toupper(*scriptChars);
} else {
@@ -204,7 +203,7 @@ void AaptLocaleValue::setScript(const char* scriptChars) {
void AaptLocaleValue::setVariant(const char* variantChars) {
size_t i = 0;
- while ((*variantChars) != '\0') {
+ while ((*variantChars) != '\0' && i < sizeof(variant)/sizeof(variant[0])) {
variant[i++] = *variantChars;
variantChars++;
}
@@ -346,7 +345,8 @@ int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int sta
return ++currentIndex;
} else {
- if ((part.length() == 2 || part.length() == 3) && isAlpha(part)) {
+ if ((part.length() == 2 || part.length() == 3)
+ && isAlpha(part) && strcmp("car", part.string())) {
setLanguage(part);
if (++currentIndex == size) {
return size;
@@ -1241,7 +1241,7 @@ bail:
}
ssize_t
-AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
+AaptAssets::slurpResourceZip(Bundle* /* bundle */, const char* filename)
{
int count = 0;
SortedVector<AaptGroupEntry> entries;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index bc9c1f70b8c6..c5495a55848d 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -36,7 +36,6 @@ aaptSources := \
Images.cpp \
Package.cpp \
pseudolocalize.cpp \
- qsort_r_compat.c \
Resource.cpp \
ResourceFilter.cpp \
ResourceIdCache.cpp \
@@ -68,6 +67,7 @@ aaptHostStaticLibs := \
libziparchive-host
aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER)\"
+aaptCFLAGS += -Wall -Werror
ifeq ($(HOST_OS),linux)
aaptHostLdLibs += -lrt -ldl -lpthread
@@ -118,6 +118,7 @@ include $(BUILD_HOST_EXECUTABLE)
# Build the host tests: libaapt_tests
# ==========================================================
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := libaapt_tests
LOCAL_CFLAGS += $(aaptCFlags)
@@ -139,10 +140,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := aapt
LOCAL_CFLAGS += $(aaptCFlags)
LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
-LOCAL_C_INCLUDES += \
- $(aaptCIncludes) \
- bionic \
- external/stlport/stlport
+LOCAL_C_INCLUDES += $(aaptCIncludes)
LOCAL_SHARED_LIBRARIES := \
libandroidfw \
libutils \
@@ -151,7 +149,6 @@ LOCAL_SHARED_LIBRARIES := \
liblog \
libz
LOCAL_STATIC_LIBRARIES := \
- libstlport_static \
libexpat_static
include $(BUILD_EXECUTABLE)
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 3fa131edd873..8a0a39cfb445 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -215,14 +215,15 @@ int doList(Bundle* bundle)
goto bail;
}
+#ifdef HAVE_ANDROID_OS
+ static const bool kHaveAndroidOs = true;
+#else
+ static const bool kHaveAndroidOs = false;
+#endif
const ResTable& res = assets.getResources(false);
- if (&res == NULL) {
- printf("\nNo resource table found.\n");
- } else {
-#ifndef HAVE_ANDROID_OS
+ if (!kHaveAndroidOs) {
printf("\nResource table:\n");
res.print(false);
-#endif
}
Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -620,10 +621,7 @@ int doDump(Bundle* bundle)
assets.setConfiguration(config);
const ResTable& res = assets.getResources(false);
- if (&res == NULL) {
- fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
- return 1;
- } else if (res.getError() != NO_ERROR) {
+ if (res.getError() != NO_ERROR) {
fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
return 1;
}
diff --git a/tools/aapt/CrunchCache.cpp b/tools/aapt/CrunchCache.cpp
index c4cf6bc8494f..6c39d1d7753c 100644
--- a/tools/aapt/CrunchCache.cpp
+++ b/tools/aapt/CrunchCache.cpp
@@ -101,4 +101,4 @@ bool CrunchCache::needsUpdating(String8 relativePath) const
time_t sourceDate = mSourceFiles.valueFor(mSourcePath.appendPathCopy(relativePath));
time_t destDate = mDestFiles.valueFor(mDestPath.appendPathCopy(relativePath));
return sourceDate > destDate;
-} \ No newline at end of file
+}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 5d4a6ac8e0c6..063b4e6801a0 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -14,7 +14,8 @@
#include <png.h>
#include <zlib.h>
-#define NOISY(x) //x
+// Change this to true for noisy debug output.
+static const bool kIsDebug = false;
static void
png_write_aapt_file(png_structp png_ptr, png_bytep data, png_size_t length)
@@ -28,7 +29,7 @@ png_write_aapt_file(png_structp png_ptr, png_bytep data, png_size_t length)
static void
-png_flush_aapt_file(png_structp png_ptr)
+png_flush_aapt_file(png_structp /* png_ptr */)
{
}
@@ -156,11 +157,13 @@ static void read_png(const char* imageName,
png_read_end(read_ptr, read_info);
- NOISY(printf("Image %s: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
- imageName,
- (int)outImageInfo->width, (int)outImageInfo->height,
- bit_depth, color_type,
- interlace_type, compression_type));
+ if (kIsDebug) {
+ printf("Image %s: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
+ imageName,
+ (int)outImageInfo->width, (int)outImageInfo->height,
+ bit_depth, color_type,
+ interlace_type, compression_type);
+ }
png_get_IHDR(read_ptr, read_info, &outImageInfo->width,
&outImageInfo->height, &bit_depth, &color_type,
@@ -330,7 +333,7 @@ static status_t get_vertical_ticks(
}
static status_t get_horizontal_layout_bounds_ticks(
- png_bytep row, int width, bool transparent, bool required,
+ png_bytep row, int width, bool transparent, bool /* required */,
int32_t* outLeft, int32_t* outRight, const char** outError)
{
int i;
@@ -368,7 +371,7 @@ static status_t get_horizontal_layout_bounds_ticks(
}
static status_t get_vertical_layout_bounds_ticks(
- png_bytepp rows, int offset, int height, bool transparent, bool required,
+ png_bytepp rows, int offset, int height, bool transparent, bool /* required */,
int32_t* outTop, int32_t* outBottom, const char** outError)
{
int i;
@@ -478,8 +481,9 @@ static void get_outline(image_info* image)
// assuming the image is a round rect, compute the radius by marching
// diagonally from the top left corner towards the center
- image->outlineAlpha = max(max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
- max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
+ image->outlineAlpha = std::max(
+ max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
+ max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
int diagonalInset = 0;
find_max_opacity(image->rows, innerStartX, innerStartY, innerMidX, innerMidY, 1, 1,
@@ -493,13 +497,15 @@ static void get_outline(image_info* image)
*/
image->outlineRadius = 3.4142f * diagonalInset;
- NOISY(printf("outline insets %d %d %d %d, rad %f, alpha %x\n",
- image->outlineInsetsLeft,
- image->outlineInsetsTop,
- image->outlineInsetsRight,
- image->outlineInsetsBottom,
- image->outlineRadius,
- image->outlineAlpha));
+ if (kIsDebug) {
+ printf("outline insets %d %d %d %d, rad %f, alpha %x\n",
+ image->outlineInsetsLeft,
+ image->outlineInsetsTop,
+ image->outlineInsetsRight,
+ image->outlineInsetsBottom,
+ image->outlineRadius,
+ image->outlineAlpha);
+ }
}
@@ -533,41 +539,6 @@ static uint32_t get_color(
return (color[3]<<24) | (color[0]<<16) | (color[1]<<8) | color[2];
}
-static void select_patch(
- int which, int front, int back, int size, int* start, int* end)
-{
- switch (which) {
- case 0:
- *start = 0;
- *end = front-1;
- break;
- case 1:
- *start = front;
- *end = back-1;
- break;
- case 2:
- *start = back;
- *end = size-1;
- break;
- }
-}
-
-static uint32_t get_color(image_info* image, int hpatch, int vpatch)
-{
- int left, right, top, bottom;
- select_patch(
- hpatch, image->xDivs[0], image->xDivs[1],
- image->width, &left, &right);
- select_patch(
- vpatch, image->yDivs[0], image->yDivs[1],
- image->height, &top, &bottom);
- //printf("Selecting h=%d v=%d: (%d,%d)-(%d,%d)\n",
- // hpatch, vpatch, left, top, right, bottom);
- const uint32_t c = get_color(image->rows, left, top, right, bottom);
- NOISY(printf("Color in (%d,%d)-(%d,%d): #%08x\n", left, top, right, bottom, c));
- return c;
-}
-
static status_t do_9patch(const char* imageName, image_info* image)
{
image->is9Patch = true;
@@ -672,8 +643,10 @@ static status_t do_9patch(const char* imageName, image_info* image)
|| image->layoutBoundsBottom != 0;
if (image->haveLayoutBounds) {
- NOISY(printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop,
- image->layoutBoundsRight, image->layoutBoundsBottom));
+ if (kIsDebug) {
+ printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop,
+ image->layoutBoundsRight, image->layoutBoundsBottom);
+ }
}
// use opacity of pixels to estimate the round rect outline
@@ -695,12 +668,14 @@ static status_t do_9patch(const char* imageName, image_info* image)
image->info9Patch.paddingBottom = H - 2 - image->info9Patch.paddingBottom;
}
- NOISY(printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName,
- xDivs[0], xDivs[1],
- yDivs[0], yDivs[1]));
- NOISY(printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName,
- image->info9Patch.paddingLeft, image->info9Patch.paddingRight,
- image->info9Patch.paddingTop, image->info9Patch.paddingBottom));
+ if (kIsDebug) {
+ printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName,
+ xDivs[0], xDivs[1],
+ yDivs[0], yDivs[1]);
+ printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName,
+ image->info9Patch.paddingLeft, image->info9Patch.paddingRight,
+ image->info9Patch.paddingTop, image->info9Patch.paddingBottom);
+ }
// Remove frame from image.
image->rows = (png_bytepp)malloc((H-2) * sizeof(png_bytep));
@@ -782,7 +757,10 @@ static status_t do_9patch(const char* imageName, image_info* image)
}
c = get_color(image->rows, left, top, right - 1, bottom - 1);
image->colors[colorIndex++] = c;
- NOISY(if (c != Res_png_9patch::NO_COLOR) hasColor = true);
+ if (kIsDebug) {
+ if (c != Res_png_9patch::NO_COLOR)
+ hasColor = true;
+ }
left = right;
}
top = bottom;
@@ -885,7 +863,7 @@ static void dump_image(int w, int h, png_bytepp rows, int color_type)
break;
}
if (i == (w - 1)) {
- NOISY(printf("\n"));
+ printf("\n");
}
}
}
@@ -915,8 +893,10 @@ static void analyze_image(const char *imageName, image_info &imageInfo, int gray
// 2. Every pixel has A == 255 (opaque)
// 3. There are no more than 256 distinct RGBA colors
- // NOISY(printf("Initial image data:\n"));
- // dump_image(w, h, imageInfo.rows, PNG_COLOR_TYPE_RGB_ALPHA);
+ if (kIsDebug) {
+ printf("Initial image data:\n");
+ dump_image(w, h, imageInfo.rows, PNG_COLOR_TYPE_RGB_ALPHA);
+ }
for (j = 0; j < h; j++) {
png_bytep row = imageInfo.rows[j];
@@ -932,15 +912,19 @@ static void analyze_image(const char *imageName, image_info &imageInfo, int gray
maxGrayDeviation = MAX(ABS(gg - bb), maxGrayDeviation);
maxGrayDeviation = MAX(ABS(bb - rr), maxGrayDeviation);
if (maxGrayDeviation > odev) {
- NOISY(printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n",
- maxGrayDeviation, i, j, rr, gg, bb, aa));
+ if (kIsDebug) {
+ printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n",
+ maxGrayDeviation, i, j, rr, gg, bb, aa);
+ }
}
// Check if image is really grayscale
if (isGrayscale) {
if (rr != gg || rr != bb) {
- NOISY(printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n",
- i, j, rr, gg, bb, aa));
+ if (kIsDebug) {
+ printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n",
+ i, j, rr, gg, bb, aa);
+ }
isGrayscale = false;
}
}
@@ -948,8 +932,10 @@ static void analyze_image(const char *imageName, image_info &imageInfo, int gray
// Check if image is really opaque
if (isOpaque) {
if (aa != 0xff) {
- NOISY(printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n",
- i, j, rr, gg, bb, aa));
+ if (kIsDebug) {
+ printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n",
+ i, j, rr, gg, bb, aa);
+ }
isOpaque = false;
}
}
@@ -971,7 +957,9 @@ static void analyze_image(const char *imageName, image_info &imageInfo, int gray
*out++ = idx;
if (!match) {
if (num_colors == 256) {
- NOISY(printf("Found 257th color at %d, %d\n", i, j));
+ if (kIsDebug) {
+ printf("Found 257th color at %d, %d\n", i, j);
+ }
isPalette = false;
} else {
colors[num_colors++] = col;
@@ -986,12 +974,14 @@ static void analyze_image(const char *imageName, image_info &imageInfo, int gray
int bpp = isOpaque ? 3 : 4;
int paletteSize = w * h + bpp * num_colors;
- NOISY(printf("isGrayscale = %s\n", isGrayscale ? "true" : "false"));
- NOISY(printf("isOpaque = %s\n", isOpaque ? "true" : "false"));
- NOISY(printf("isPalette = %s\n", isPalette ? "true" : "false"));
- NOISY(printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n",
- paletteSize, 2 * w * h, bpp * w * h));
- NOISY(printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance));
+ if (kIsDebug) {
+ printf("isGrayscale = %s\n", isGrayscale ? "true" : "false");
+ printf("isOpaque = %s\n", isOpaque ? "true" : "false");
+ printf("isPalette = %s\n", isPalette ? "true" : "false");
+ printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n",
+ paletteSize, 2 * w * h, bpp * w * h);
+ printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance);
+ }
// Choose the best color type for the image.
// 1. Opaque gray - use COLOR_TYPE_GRAY at 1 byte/pixel
@@ -1068,7 +1058,6 @@ static void write_png(const char* imageName,
png_structp write_ptr, png_infop write_info,
image_info& imageInfo, int grayscaleTolerance)
{
- bool optimize = true;
png_uint_32 width, height;
int color_type;
int bit_depth, interlace_type, compression_type;
@@ -1094,8 +1083,10 @@ static void write_png(const char* imageName,
png_set_compression_level(write_ptr, Z_BEST_COMPRESSION);
- NOISY(printf("Writing image %s: w = %d, h = %d\n", imageName,
- (int) imageInfo.width, (int) imageInfo.height));
+ if (kIsDebug) {
+ printf("Writing image %s: w = %d, h = %d\n", imageName,
+ (int) imageInfo.width, (int) imageInfo.height);
+ }
png_color rgbPalette[256];
png_byte alphaPalette[256];
@@ -1112,24 +1103,26 @@ static void write_png(const char* imageName,
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
- switch (color_type) {
- case PNG_COLOR_TYPE_PALETTE:
- NOISY(printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n",
- imageName, paletteEntries,
- hasTransparency ? " (with alpha)" : ""));
- break;
- case PNG_COLOR_TYPE_GRAY:
- NOISY(printf("Image %s is opaque gray, using PNG_COLOR_TYPE_GRAY\n", imageName));
- break;
- case PNG_COLOR_TYPE_GRAY_ALPHA:
- NOISY(printf("Image %s is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA\n", imageName));
- break;
- case PNG_COLOR_TYPE_RGB:
- NOISY(printf("Image %s is opaque RGB, using PNG_COLOR_TYPE_RGB\n", imageName));
- break;
- case PNG_COLOR_TYPE_RGB_ALPHA:
- NOISY(printf("Image %s is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA\n", imageName));
- break;
+ if (kIsDebug) {
+ switch (color_type) {
+ case PNG_COLOR_TYPE_PALETTE:
+ printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n",
+ imageName, paletteEntries,
+ hasTransparency ? " (with alpha)" : "");
+ break;
+ case PNG_COLOR_TYPE_GRAY:
+ printf("Image %s is opaque gray, using PNG_COLOR_TYPE_GRAY\n", imageName);
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ printf("Image %s is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA\n", imageName);
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ printf("Image %s is opaque RGB, using PNG_COLOR_TYPE_RGB\n", imageName);
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ printf("Image %s is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA\n", imageName);
+ break;
+ }
}
png_set_IHDR(write_ptr, write_info, imageInfo.width, imageInfo.height,
@@ -1158,7 +1151,9 @@ static void write_png(const char* imageName,
: (png_byte*)"npOl\0npTc";
// base 9 patch data
- NOISY(printf("Adding 9-patch info...\n"));
+ if (kIsDebug) {
+ printf("Adding 9-patch info...\n");
+ }
strcpy((char*)unknowns[p_index].name, "npTc");
unknowns[p_index].data = (png_byte*)imageInfo.serialize9patch();
unknowns[p_index].size = imageInfo.info9Patch.serializedSize();
@@ -1214,8 +1209,10 @@ static void write_png(const char* imageName,
}
png_write_image(write_ptr, rows);
-// NOISY(printf("Final image data:\n"));
-// dump_image(imageInfo.width, imageInfo.height, rows, color_type);
+ if (kIsDebug) {
+ printf("Final image data:\n");
+ dump_image(imageInfo.width, imageInfo.height, rows, color_type);
+ }
png_write_end(write_ptr, write_info);
@@ -1231,13 +1228,50 @@ static void write_png(const char* imageName,
&bit_depth, &color_type, &interlace_type,
&compression_type, NULL);
- NOISY(printf("Image written: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
- (int)width, (int)height, bit_depth, color_type, interlace_type,
- compression_type));
+ if (kIsDebug) {
+ printf("Image written: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
+ (int)width, (int)height, bit_depth, color_type, interlace_type,
+ compression_type);
+ }
}
-status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
- const sp<AaptFile>& file, String8* outNewLeafName)
+static bool read_png_protected(png_structp read_ptr, String8& printableName, png_infop read_info,
+ const sp<AaptFile>& file, FILE* fp, image_info* imageInfo) {
+ if (setjmp(png_jmpbuf(read_ptr))) {
+ return false;
+ }
+
+ png_init_io(read_ptr, fp);
+
+ read_png(printableName.string(), read_ptr, read_info, imageInfo);
+
+ const size_t nameLen = file->getPath().length();
+ if (nameLen > 6) {
+ const char* name = file->getPath().string();
+ if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
+ if (do_9patch(printableName.string(), imageInfo) != NO_ERROR) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool write_png_protected(png_structp write_ptr, String8& printableName, png_infop write_info,
+ image_info* imageInfo, const Bundle* bundle) {
+ if (setjmp(png_jmpbuf(write_ptr))) {
+ return false;
+ }
+
+ write_png(printableName.string(), write_ptr, write_info, *imageInfo,
+ bundle->getGrayscaleTolerance());
+
+ return true;
+}
+
+status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets */,
+ const sp<AaptFile>& file, String8* /* outNewLeafName */)
{
String8 ext(file->getPath().getPathExtension());
@@ -1267,8 +1301,6 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
status_t error = UNKNOWN_ERROR;
- const size_t nameLen = file->getPath().length();
-
fp = fopen(file->getSourceFile().string(), "rb");
if (fp == NULL) {
fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.string());
@@ -1286,23 +1318,10 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
goto bail;
}
- if (setjmp(png_jmpbuf(read_ptr))) {
+ if (!read_png_protected(read_ptr, printableName, read_info, file, fp, &imageInfo)) {
goto bail;
}
- png_init_io(read_ptr, fp);
-
- read_png(printableName.string(), read_ptr, read_info, &imageInfo);
-
- if (nameLen > 6) {
- const char* name = file->getPath().string();
- if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
- if (do_9patch(printableName.string(), &imageInfo) != NO_ERROR) {
- goto bail;
- }
- }
- }
-
write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, (png_error_ptr)NULL,
(png_error_ptr)NULL);
if (!write_ptr)
@@ -1319,14 +1338,10 @@ status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
png_set_write_fn(write_ptr, (void*)file.get(),
png_write_aapt_file, png_flush_aapt_file);
- if (setjmp(png_jmpbuf(write_ptr)))
- {
+ if (!write_png_protected(write_ptr, printableName, write_info, &imageInfo, bundle)) {
goto bail;
}
- write_png(printableName.string(), write_ptr, write_info, imageInfo,
- bundle->getGrayscaleTolerance());
-
error = NO_ERROR;
if (bundle->getVerbose()) {
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 18b8e1ecfe49..8b416aa82fdb 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -69,7 +69,7 @@ void usage(void)
" [-S resource-sources [-S resource-sources ...]] \\\n"
" [-F apk-file] [-J R-file-dir] \\\n"
" [--product product1,product2,...] \\\n"
- " [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
+ " [-c CONFIGS] [--preferred-density DENSITY] \\\n"
" [--split CONFIGS [--split CONFIGS]] \\\n"
" [--feature-of package [--feature-after package]] \\\n"
" [raw-files-dir [raw-files-dir] ...] \\\n"
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index dc16e354b584..cb244eccfe21 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -402,7 +402,6 @@ bool endsWith(const char* haystack, const char* needle)
ssize_t processJarFile(ZipFile* jar, ZipFile* out)
{
- status_t err;
size_t N = jar->getNumEntries();
size_t count = 0;
for (size_t i=0; i<N; i++) {
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index e2e83e493e7d..36299c2c3a5b 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -20,15 +20,20 @@
#include <algorithm>
+// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
+
#if HAVE_PRINTF_ZD
# define ZD "%zd"
# define ZD_TYPE ssize_t
+# define STATUST(x) x
#else
# define ZD "%ld"
# define ZD_TYPE long
+# define STATUST(x) (status_t)x
#endif
-#define NOISY(x) // x
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
// Number of threads to use for preprocessing images.
static const size_t MAX_THREADS = 4;
@@ -129,15 +134,17 @@ public:
String8 leaf(group->getLeaf());
mLeafName = String8(leaf);
mParams = file->getGroupEntry().toParams();
- NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n",
- group->getPath().string(), mParams.mcc, mParams.mnc,
- mParams.language[0] ? mParams.language[0] : '-',
- mParams.language[1] ? mParams.language[1] : '-',
- mParams.country[0] ? mParams.country[0] : '-',
- mParams.country[1] ? mParams.country[1] : '-',
- mParams.orientation, mParams.uiMode,
- mParams.density, mParams.touchscreen, mParams.keyboard,
- mParams.inputFlags, mParams.navigation));
+ if (kIsDebug) {
+ printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n",
+ group->getPath().string(), mParams.mcc, mParams.mnc,
+ mParams.language[0] ? mParams.language[0] : '-',
+ mParams.language[1] ? mParams.language[1] : '-',
+ mParams.country[0] ? mParams.country[0] : '-',
+ mParams.country[1] ? mParams.country[1] : '-',
+ mParams.orientation, mParams.uiMode,
+ mParams.density, mParams.touchscreen, mParams.keyboard,
+ mParams.inputFlags, mParams.navigation);
+ }
mPath = "res";
mPath.appendPath(file->getGroupEntry().toDirName(mResType));
mPath.appendPath(leaf);
@@ -148,7 +155,9 @@ public:
return UNKNOWN_ERROR;
}
- NOISY(printf("file name=%s\n", mBaseName.string()));
+ if (kIsDebug) {
+ printf("file name=%s\n", mBaseName.string());
+ }
return NO_ERROR;
}
@@ -326,7 +335,7 @@ static status_t makeFileResources(Bundle* bundle, const sp<AaptAssets>& assets,
assets->addResource(it.getLeafName(), resPath, it.getFile(), type8);
}
- return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+ return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
class PreProcessImageWorkUnit : public WorkQueue::WorkUnit {
@@ -376,7 +385,7 @@ static status_t preProcessImages(const Bundle* bundle, const sp<AaptAssets>& ass
hasErrors = true;
}
}
- return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
+ return (hasErrors || (res < NO_ERROR)) ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
static void collect_files(const sp<AaptDir>& dir,
@@ -401,27 +410,35 @@ static void collect_files(const sp<AaptDir>& dir,
if (index < 0) {
sp<ResourceTypeSet> set = new ResourceTypeSet();
- NOISY(printf("Creating new resource type set for leaf %s with group %s (%p)\n",
- leafName.string(), group->getPath().string(), group.get()));
+ if (kIsDebug) {
+ printf("Creating new resource type set for leaf %s with group %s (%p)\n",
+ leafName.string(), group->getPath().string(), group.get());
+ }
set->add(leafName, group);
resources->add(resType, set);
} else {
sp<ResourceTypeSet> set = resources->valueAt(index);
index = set->indexOfKey(leafName);
if (index < 0) {
- NOISY(printf("Adding to resource type set for leaf %s group %s (%p)\n",
- leafName.string(), group->getPath().string(), group.get()));
+ if (kIsDebug) {
+ printf("Adding to resource type set for leaf %s group %s (%p)\n",
+ leafName.string(), group->getPath().string(), group.get());
+ }
set->add(leafName, group);
} else {
sp<AaptGroup> existingGroup = set->valueAt(index);
- NOISY(printf("Extending to resource type set for leaf %s group %s (%p)\n",
- leafName.string(), group->getPath().string(), group.get()));
+ if (kIsDebug) {
+ printf("Extending to resource type set for leaf %s group %s (%p)\n",
+ leafName.string(), group->getPath().string(), group.get());
+ }
for (size_t j=0; j<files.size(); j++) {
- NOISY(printf("Adding file %s in group %s resType %s\n",
- files.valueAt(j)->getSourceFile().string(),
- files.keyAt(j).toDirName(String8()).string(),
- resType.string()));
- status_t err = existingGroup->addFile(files.valueAt(j));
+ if (kIsDebug) {
+ printf("Adding file %s in group %s resType %s\n",
+ files.valueAt(j)->getSourceFile().string(),
+ files.keyAt(j).toDirName(String8()).string(),
+ resType.string());
+ }
+ existingGroup->addFile(files.valueAt(j));
}
}
}
@@ -436,12 +453,16 @@ static void collect_files(const sp<AaptAssets>& ass,
for (int i=0; i<N; i++) {
sp<AaptDir> d = dirs.itemAt(i);
- NOISY(printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(),
- d->getLeaf().string()));
+ if (kIsDebug) {
+ printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(),
+ d->getLeaf().string());
+ }
collect_files(d, resources);
// don't try to include the res dir
- NOISY(printf("Removing dir leaf %s\n", d->getLeaf().string()));
+ if (kIsDebug) {
+ printf("Removing dir leaf %s\n", d->getLeaf().string());
+ }
ass->removeDir(d->getLeaf());
}
}
@@ -536,7 +557,7 @@ static int validateAttr(const String8& path, const ResTable& table,
String8(parser.getElementName(&len)).string(), attr);
return ATTR_LEADING_SPACES;
}
- if (str[len-1] == ' ') {
+ if (len != 0 && str[len-1] == ' ') {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not end with a space.\n",
path.string(), parser.getLineNumber(),
String8(parser.getElementName(&len)).string(), attr);
@@ -699,9 +720,11 @@ bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
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()));
+ if (kIsDebug) {
+ 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;
}
@@ -760,7 +783,9 @@ static void fullyQualifyClassName(const String8& package, sp<XMLNode> node,
} else {
className += name;
}
- NOISY(printf("Qualifying class '%s' to '%s'", name.string(), className.string()));
+ if (kIsDebug) {
+ printf("Qualifying class '%s' to '%s'", name.string(), className.string());
+ }
attr->string.setTo(String16(className));
}
}
@@ -864,7 +889,10 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
}
String8 origPackage(attr->string);
attr->string.setTo(String16(manifestPackageNameOverride));
- NOISY(printf("Overriding package '%s' to be '%s'\n", origPackage.string(), manifestPackageNameOverride));
+ if (kIsDebug) {
+ printf("Overriding package '%s' to be '%s'\n", origPackage.string(),
+ manifestPackageNameOverride);
+ }
// Make class names fully qualified
sp<XMLNode> application = root->getChildElement(String16(), String16("application"));
@@ -1129,8 +1157,9 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
return err;
}
- NOISY(printf("Creating resources for package %s\n",
- assets->getPackage().string()));
+ if (kIsDebug) {
+ printf("Creating resources for package %s\n", assets->getPackage().string());
+ }
ResourceTable::PackageType packageType = ResourceTable::App;
if (bundle->getBuildSharedLibrary()) {
@@ -1147,7 +1176,9 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
return err;
}
- NOISY(printf("Found %d included resource packages\n", (int)table.size()));
+ if (kIsDebug) {
+ printf("Found %d included resource packages\n", (int)table.size());
+ }
// Standard flags for compiled XML and optional UTF-8 encoding
int xmlFlags = XML_COMPILE_STANDARD_RESOURCE;
@@ -2052,7 +2083,7 @@ static String16 getAttributeComment(const sp<AaptAssets>& assets,
static status_t writeResourceLoadedCallbackForLayoutClasses(
FILE* fp, const sp<AaptAssets>& assets,
- const sp<AaptSymbols>& symbols, int indent, bool includePrivate)
+ const sp<AaptSymbols>& symbols, int indent, bool /* includePrivate */)
{
String16 attr16("attr");
String16 package16(assets->getPackage());
@@ -2356,7 +2387,7 @@ static status_t writeLayoutClasses(
indent--;
fprintf(fp, "%s};\n", getIndentSpace(indent));
- return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+ return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
static status_t writeTextLayoutClasses(
@@ -2442,7 +2473,7 @@ static status_t writeTextLayoutClasses(
package16.string(), package16.size(), &typeSpecFlags);
//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;
+ //const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
fprintf(fp,
"int styleable %s_%s %d\n",
@@ -2452,7 +2483,7 @@ static status_t writeTextLayoutClasses(
}
}
- return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+ return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
static status_t writeSymbolClass(
@@ -2783,7 +2814,7 @@ addProguardKeepRule(ProguardKeepSet* keep, const String8& inClassName,
void
addProguardKeepMethodRule(ProguardKeepSet* keep, const String8& memberName,
- const char* pkg, const String8& srcName, int line)
+ const char* /* pkg */, const String8& srcName, int line)
{
String8 rule("-keepclassmembers class * { *** ");
rule += memberName;
@@ -3123,7 +3154,7 @@ status_t writePathsToFile(const sp<FilePathStore>& files, FILE* fp)
}
status_t
-writeDependencyPreReqs(Bundle* bundle, const sp<AaptAssets>& assets, FILE* fp, bool includeRaw)
+writeDependencyPreReqs(Bundle* /* bundle */, const sp<AaptAssets>& assets, FILE* fp, bool includeRaw)
{
status_t deps = -1;
deps += writePathsToFile(assets->getFullResPaths(), fp);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index e000a1dc1feb..941a2884e2a6 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -18,7 +18,24 @@
#include <utils/TypeHelpers.h>
#include <stdarg.h>
-#define NOISY(x) //x
+// SSIZE: mingw does not have signed size_t == ssize_t.
+// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
+#if HAVE_PRINTF_ZD
+# define SSIZE(x) x
+# define STATUST(x) x
+#else
+# define SSIZE(x) (signed size_t)x
+# define STATUST(x) (status_t)x
+#endif
+
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
+
+#if PRINT_STRING_METRICS
+static const bool kPrintStringMetrics = true;
+#else
+static const bool kPrintStringMetrics = false;
+#endif
static const char* kAttrPrivateType = "^attr-private";
@@ -92,9 +109,11 @@ status_t compileXmlFile(const Bundle* bundle,
if (table->modifyForCompat(bundle, resourceName, target, root) != NO_ERROR) {
return UNKNOWN_ERROR;
}
-
- NOISY(printf("Input XML Resource:\n"));
- NOISY(root->print());
+
+ if (kIsDebug) {
+ printf("Input XML Resource:\n");
+ root->print();
+ }
err = root->flatten(target,
(options&XML_COMPILE_STRIP_COMMENTS) != 0,
(options&XML_COMPILE_STRIP_RAW_VALUES) != 0);
@@ -102,19 +121,18 @@ status_t compileXmlFile(const Bundle* bundle,
return err;
}
- NOISY(printf("Output XML Resource:\n"));
- NOISY(ResXMLTree tree;
+ if (kIsDebug) {
+ printf("Output XML Resource:\n");
+ ResXMLTree tree;
tree.setTo(target->getData(), target->getSize());
- printXMLBlock(&tree));
+ printXMLBlock(&tree);
+ }
target->setCompressionMethod(ZipEntry::kCompressDeflated);
return err;
}
-#undef NOISY
-#define NOISY(x) //x
-
struct flag_entry
{
const char16_t* name;
@@ -583,7 +601,7 @@ status_t parseAndAddBag(Bundle* bundle,
const String16& itemIdent,
int32_t curFormat,
bool isFormatted,
- const String16& product,
+ const String16& /* product */,
PseudolocalizationMethod pseudolocalize,
const bool overwrite,
ResourceTable* outTable)
@@ -599,16 +617,18 @@ status_t parseAndAddBag(Bundle* bundle,
if (err != NO_ERROR) {
return err;
}
-
- NOISY(printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d "
- " pid=%s, bag=%s, id=%s: %s\n",
- config.language[0], config.language[1],
- config.country[0], config.country[1],
- config.orientation, config.density,
- String8(parentIdent).string(),
- String8(ident).string(),
- String8(itemIdent).string(),
- String8(str).string()));
+
+ if (kIsDebug) {
+ printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d "
+ " pid=%s, bag=%s, id=%s: %s\n",
+ config.language[0], config.language[1],
+ config.country[0], config.country[1],
+ config.orientation, config.density,
+ String8(parentIdent).string(),
+ String8(ident).string(),
+ String8(itemIdent).string(),
+ String8(str).string());
+ }
err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()),
myPackage, curType, ident, parentIdent, itemIdent, str,
@@ -744,11 +764,13 @@ status_t parseAndAddEntry(Bundle* bundle,
}
}
- NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n",
- config.language[0], config.language[1],
- config.country[0], config.country[1],
- config.orientation, config.density,
- String8(ident).string(), String8(str).string()));
+ if (kIsDebug) {
+ printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n",
+ config.language[0], config.language[1],
+ config.country[0], config.country[1],
+ config.orientation, config.density,
+ String8(ident).string(), String8(str).string());
+ }
err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
myPackage, curType, ident, str, &spans, &config,
@@ -1717,7 +1739,7 @@ status_t compileResourceFile(Bundle* bundle,
}
}
- return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+ return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, ResourceTable::PackageType type)
@@ -1785,7 +1807,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets
}
const ResTable& featureTable = featureAssetManager.getResources(false);
- mTypeIdOffset = max(mTypeIdOffset,
+ mTypeIdOffset = std::max(mTypeIdOffset,
findLargestTypeIdForPackage(featureTable, mAssetsPackage));
}
@@ -1856,7 +1878,7 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
const String16& bagParent,
const ResTable_config* params,
bool overlay,
- bool replace, bool isId)
+ bool replace, bool /* isId */)
{
status_t result = NO_ERROR;
@@ -2163,22 +2185,25 @@ uint32_t ResourceTable::getResId(const String16& ref,
ref.string(), ref.size(), &package, &type, &name,
defType, defPackage ? defPackage:&mAssetsPackage,
outErrorMsg, &refOnlyPublic)) {
- NOISY(printf("Expanding resource: ref=%s\n",
- String8(ref).string()));
- NOISY(printf("Expanding resource: defType=%s\n",
- defType ? String8(*defType).string() : "NULL"));
- NOISY(printf("Expanding resource: defPackage=%s\n",
- defPackage ? String8(*defPackage).string() : "NULL"));
- NOISY(printf("Expanding resource: ref=%s\n", String8(ref).string()));
- NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
- String8(package).string(), String8(type).string(),
- String8(name).string()));
+ if (kIsDebug) {
+ printf("Expanding resource: ref=%s\n", String8(ref).string());
+ printf("Expanding resource: defType=%s\n",
+ defType ? String8(*defType).string() : "NULL");
+ printf("Expanding resource: defPackage=%s\n",
+ defPackage ? String8(*defPackage).string() : "NULL");
+ printf("Expanding resource: ref=%s\n", String8(ref).string());
+ printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
+ String8(package).string(), String8(type).string(),
+ String8(name).string());
+ }
return 0;
}
uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic);
- NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
- String8(package).string(), String8(type).string(),
- String8(name).string(), res));
+ if (kIsDebug) {
+ printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
+ String8(package).string(), String8(type).string(),
+ String8(name).string(), res);
+ }
if (res == 0) {
if (outErrorMsg)
*outErrorMsg = "No resource found that matches the given name";
@@ -2245,9 +2270,11 @@ bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
} else {
configStr = "(null)";
}
- NOISY(printf("Adding to pool string style #%d config %s: %s\n",
- style != NULL ? style->size() : 0,
- configStr.string(), String8(finalStr).string()));
+ if (kIsDebug) {
+ printf("Adding to pool string style #%zu config %s: %s\n",
+ style != NULL ? style->size() : 0U,
+ configStr.string(), String8(finalStr).string());
+ }
if (style != NULL && style->size() > 0) {
outValue->data = pool->add(finalStr, *style, configTypeName, config);
} else {
@@ -2676,20 +2703,16 @@ ResourceTable::validateLocalizations(void)
const String8 defaultLocale;
// For all strings...
- for (map<String16, map<String8, SourcePos> >::iterator nameIter = mLocalizations.begin();
- nameIter != mLocalizations.end();
- nameIter++) {
- const map<String8, SourcePos>& configSrcMap = nameIter->second;
+ for (const auto& nameIter : mLocalizations) {
+ const std::map<String8, SourcePos>& configSrcMap = nameIter.second;
// Look for strings with no default localization
if (configSrcMap.count(defaultLocale) == 0) {
SourcePos().warning("string '%s' has no default translation.",
- String8(nameIter->first).string());
+ String8(nameIter.first).string());
if (mBundle->getVerbose()) {
- for (map<String8, SourcePos>::const_iterator locales = configSrcMap.begin();
- locales != configSrcMap.end();
- locales++) {
- locales->second.printf("locale %s found", locales->first.string());
+ for (const auto& locale : configSrcMap) {
+ locale.second.printf("locale %s found", locale.first.string());
}
}
// !!! TODO: throw an error here in some circumstances
@@ -2700,8 +2723,8 @@ ResourceTable::validateLocalizations(void)
const char* allConfigs = mBundle->getConfigurations().string();
const char* start = allConfigs;
const char* comma;
-
- set<String8> missingConfigs;
+
+ std::set<String8> missingConfigs;
AaptLocaleValue locale;
do {
String8 config;
@@ -2735,13 +2758,11 @@ ResourceTable::validateLocalizations(void)
if (!missingConfigs.empty()) {
String8 configStr;
- for (set<String8>::iterator iter = missingConfigs.begin();
- iter != missingConfigs.end();
- iter++) {
- configStr.appendFormat(" %s", iter->string());
+ for (const auto& iter : missingConfigs) {
+ configStr.appendFormat(" %s", iter.string());
}
SourcePos().warning("string '%s' is missing %u required localizations:%s",
- String8(nameIter->first).string(),
+ String8(nameIter.first).string(),
(unsigned int)missingConfigs.size(),
configStr.string());
}
@@ -2914,9 +2935,9 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
const size_t typeStringsStart = data->getSize();
sp<AaptFile> strFile = p->getTypeStringsData();
ssize_t amt = data->writeData(strFile->getData(), strFile->getSize());
- #if PRINT_STRING_METRICS
- fprintf(stderr, "**** type strings: %d\n", amt);
- #endif
+ if (kPrintStringMetrics) {
+ fprintf(stderr, "**** type strings: %zd\n", SSIZE(amt));
+ }
strAmt += amt;
if (amt < 0) {
return amt;
@@ -2924,9 +2945,9 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
const size_t keyStringsStart = data->getSize();
strFile = p->getKeyStringsData();
amt = data->writeData(strFile->getData(), strFile->getSize());
- #if PRINT_STRING_METRICS
- fprintf(stderr, "**** key strings: %d\n", amt);
- #endif
+ if (kPrintStringMetrics) {
+ fprintf(stderr, "**** key strings: %zd\n", SSIZE(amt));
+ }
strAmt += amt;
if (amt < 0) {
return amt;
@@ -3022,36 +3043,41 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
// We need to write one type chunk for each configuration for
// which we have entries in this type.
- const SortedVector<ConfigDescription> uniqueConfigs(t->getUniqueConfigs());
- const size_t NC = uniqueConfigs.size();
+ SortedVector<ConfigDescription> uniqueConfigs;
+ if (t != NULL) {
+ uniqueConfigs = t->getUniqueConfigs();
+ }
const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N;
+ const size_t NC = uniqueConfigs.size();
for (size_t ci=0; ci<NC; ci++) {
const ConfigDescription& config = uniqueConfigs[ci];
- NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c "
- "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
- "sw%ddp w%ddp h%ddp dir:%d\n",
- ti+1,
- config.mcc, config.mnc,
- config.language[0] ? config.language[0] : '-',
- config.language[1] ? config.language[1] : '-',
- config.country[0] ? config.country[0] : '-',
- config.country[1] ? config.country[1] : '-',
- config.orientation,
- config.uiMode,
- config.touchscreen,
- config.density,
- config.keyboard,
- config.inputFlags,
- config.navigation,
- config.screenWidth,
- config.screenHeight,
- config.smallestScreenWidthDp,
- config.screenWidthDp,
- config.screenHeightDp,
- config.layoutDirection));
+ if (kIsDebug) {
+ printf("Writing config %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
+ "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
+ "sw%ddp w%ddp h%ddp layout:%d\n",
+ ti + 1,
+ config.mcc, config.mnc,
+ config.language[0] ? config.language[0] : '-',
+ config.language[1] ? config.language[1] : '-',
+ config.country[0] ? config.country[0] : '-',
+ config.country[1] ? config.country[1] : '-',
+ config.orientation,
+ config.uiMode,
+ config.touchscreen,
+ config.density,
+ config.keyboard,
+ config.inputFlags,
+ config.navigation,
+ config.screenWidth,
+ config.screenHeight,
+ config.smallestScreenWidthDp,
+ config.screenWidthDp,
+ config.screenHeightDp,
+ config.screenLayout);
+ }
if (filterable && !filter->match(config)) {
continue;
@@ -3073,28 +3099,30 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
tHeader->entryCount = htodl(N);
tHeader->entriesStart = htodl(typeSize);
tHeader->config = config;
- NOISY(printf("Writing type %d config: imsi:%d/%d lang:%c%c cnt:%c%c "
- "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
- "sw%ddp w%ddp h%ddp dir:%d\n",
- ti+1,
- tHeader->config.mcc, tHeader->config.mnc,
- tHeader->config.language[0] ? tHeader->config.language[0] : '-',
- tHeader->config.language[1] ? tHeader->config.language[1] : '-',
- tHeader->config.country[0] ? tHeader->config.country[0] : '-',
- tHeader->config.country[1] ? tHeader->config.country[1] : '-',
- tHeader->config.orientation,
- tHeader->config.uiMode,
- tHeader->config.touchscreen,
- tHeader->config.density,
- tHeader->config.keyboard,
- tHeader->config.inputFlags,
- tHeader->config.navigation,
- tHeader->config.screenWidth,
- tHeader->config.screenHeight,
- tHeader->config.smallestScreenWidthDp,
- tHeader->config.screenWidthDp,
- tHeader->config.screenHeightDp,
- tHeader->config.layoutDirection));
+ if (kIsDebug) {
+ printf("Writing type %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
+ "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
+ "sw%ddp w%ddp h%ddp layout:%d\n",
+ ti + 1,
+ tHeader->config.mcc, tHeader->config.mnc,
+ tHeader->config.language[0] ? tHeader->config.language[0] : '-',
+ tHeader->config.language[1] ? tHeader->config.language[1] : '-',
+ tHeader->config.country[0] ? tHeader->config.country[0] : '-',
+ tHeader->config.country[1] ? tHeader->config.country[1] : '-',
+ tHeader->config.orientation,
+ tHeader->config.uiMode,
+ tHeader->config.touchscreen,
+ tHeader->config.density,
+ tHeader->config.keyboard,
+ tHeader->config.inputFlags,
+ tHeader->config.navigation,
+ tHeader->config.screenWidth,
+ tHeader->config.screenHeight,
+ tHeader->config.smallestScreenWidthDp,
+ tHeader->config.screenWidthDp,
+ tHeader->config.screenHeightDp,
+ tHeader->config.screenLayout);
+ }
tHeader->config.swapHtoD();
// Build the entries inside of this type.
@@ -3189,10 +3217,10 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
ssize_t amt = (dest->getSize()-strStart);
strAmt += amt;
- #if PRINT_STRING_METRICS
- fprintf(stderr, "**** value strings: %d\n", amt);
- fprintf(stderr, "**** total strings: %d\n", strAmt);
- #endif
+ if (kPrintStringMetrics) {
+ fprintf(stderr, "**** value strings: %zd\n", SSIZE(amt));
+ fprintf(stderr, "**** total strings: %zd\n", SSIZE(strAmt));
+ }
for (pi=0; pi<flatPackages.size(); pi++) {
err = dest->writeData(flatPackages[pi]->getData(),
@@ -3207,13 +3235,10 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
(((uint8_t*)dest->getData()) + dataStart);
header->header.size = htodl(dest->getSize() - dataStart);
- NOISY(aout << "Resource table:"
- << HexDump(dest->getData(), dest->getSize()) << endl);
-
- #if PRINT_STRING_METRICS
- fprintf(stderr, "**** total resource table size: %d / %d%% strings\n",
- dest->getSize(), (strAmt*100)/dest->getSize());
- #endif
+ if (kPrintStringMetrics) {
+ fprintf(stderr, "**** total resource table size: %zu / %zu%% strings\n",
+ dest->getSize(), (size_t)(strAmt*100)/dest->getSize());
+ }
return NO_ERROR;
}
@@ -3221,7 +3246,9 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
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"));
+ if (kIsDebug) {
+ fprintf(stderr, "Writing library reference table\n");
+ }
const size_t libStart = dest->getSize();
const size_t count = libs.size();
@@ -3238,9 +3265,11 @@ status_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vect
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",
+ if (kIsDebug) {
+ fprintf(stderr, " Entry %s -> 0x%02x\n",
String8(libPackage->getName()).string(),
- (uint8_t)libPackage->getAssignedId()));
+ (uint8_t)libPackage->getAssignedId());
+ }
ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(
entryStart, sizeof(ResTable_lib_entry));
@@ -3488,9 +3517,11 @@ status_t ResourceTable::Entry::generateAttributes(ResourceTable* table,
if (it.isId) {
if (!table->hasBagOrEntry(key, &id16, &package)) {
String16 value("false");
- NOISY(fprintf(stderr, "Generating %s:id/%s\n",
- String8(package).string(),
- String8(key).string()));
+ if (kIsDebug) {
+ fprintf(stderr, "Generating %s:id/%s\n",
+ String8(package).string(),
+ String8(key).string());
+ }
status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package,
id16, key, value);
if (err != NO_ERROR) {
@@ -3523,7 +3554,7 @@ status_t ResourceTable::Entry::generateAttributes(ResourceTable* table,
}
status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table,
- const String16& package)
+ const String16& /* package */)
{
bool hasErrors = false;
@@ -3556,7 +3587,7 @@ status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table,
}
}
}
- return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+ return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table,
@@ -3615,22 +3646,20 @@ status_t ResourceTable::Entry::remapStringValue(StringPool* strings)
return NO_ERROR;
}
-ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp<AaptFile>& data, bool isPublic)
+ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp<AaptFile>& data, bool isPublic)
{
size_t amt = 0;
ResTable_entry header;
memset(&header, 0, sizeof(header));
header.size = htods(sizeof(header));
- const type ty = this != NULL ? mType : TYPE_ITEM;
- if (this != NULL) {
- if (ty == TYPE_BAG) {
- header.flags |= htods(header.FLAG_COMPLEX);
- }
- if (isPublic) {
- header.flags |= htods(header.FLAG_PUBLIC);
- }
- header.key.index = htodl(mNameIndex);
+ const type ty = mType;
+ if (ty == TYPE_BAG) {
+ header.flags |= htods(header.FLAG_COMPLEX);
+ }
+ if (isPublic) {
+ header.flags |= htods(header.FLAG_PUBLIC);
}
+ header.key.index = htodl(mNameIndex);
if (ty != TYPE_BAG) {
status_t err = data->writeData(&header, sizeof(header));
if (err != NO_ERROR) {
@@ -3805,10 +3834,11 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
sp<Entry> e = c->getEntries().valueFor(cdesc);
if (e == NULL) {
- if (config != NULL) {
- NOISY(printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
+ if (kIsDebug) {
+ if (config != NULL) {
+ printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
"orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
- "sw%ddp w%ddp h%ddp dir:%d\n",
+ "sw%ddp w%ddp h%ddp layout:%d\n",
sourcePos.file.string(), sourcePos.line,
config->mcc, config->mnc,
config->language[0] ? config->language[0] : '-',
@@ -3826,10 +3856,11 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
config->smallestScreenWidthDp,
config->screenWidthDp,
config->screenHeightDp,
- config->layoutDirection));
- } else {
- NOISY(printf("New entry at %s:%d: NULL config\n",
- sourcePos.file.string(), sourcePos.line));
+ config->screenLayout);
+ } else {
+ printf("New entry at %s:%d: NULL config\n",
+ sourcePos.file.string(), sourcePos.line);
+ }
}
e = new Entry(entry, sourcePos);
c->addEntry(cdesc, e);
@@ -3968,7 +3999,7 @@ status_t ResourceTable::Type::applyPublicEntryOrder()
j++;
}
- return hasError ? UNKNOWN_ERROR : NO_ERROR;
+ return hasError ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
ResourceTable::Package::Package(const String16& name, size_t packageId)
@@ -4032,9 +4063,6 @@ status_t ResourceTable::Package::setStrings(const sp<AaptFile>& data,
return UNKNOWN_ERROR;
}
- NOISY(aout << "Setting restable string pool: "
- << HexDump(data->getData(), data->getSize()) << endl);
-
status_t err = strings->setTo(data->getData(), data->getSize());
if (err == NO_ERROR) {
const size_t N = strings->size();
@@ -4313,7 +4341,7 @@ bool ResourceTable::getItemValue(
}
item->evaluating = true;
res = stringToValue(outValue, NULL, item->value, false, false, item->bagKeyId);
- NOISY(
+ if (kIsDebug) {
if (res) {
printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n",
resID, attrID, String8(getEntry(resID)->getName()).string(),
@@ -4322,7 +4350,7 @@ bool ResourceTable::getItemValue(
printf("getItemValue of #%08x[#%08x]: failed\n",
resID, attrID);
}
- );
+ }
item->evaluating = false;
}
return res;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index eef0ae10e60d..96442248d296 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -17,8 +17,6 @@
#include "StringPool.h"
#include "Symbol.h"
-using namespace std;
-
class XMLNode;
class ResourceTable;
@@ -29,7 +27,7 @@ enum {
XML_COMPILE_STRIP_WHITESPACE = 1<<3,
XML_COMPILE_STRIP_RAW_VALUES = 1<<4,
XML_COMPILE_UTF8 = 1<<5,
-
+
XML_COMPILE_STANDARD_RESOURCE =
XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
| XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
@@ -116,7 +114,7 @@ public:
* and would mess up iteration order for the existing
* resources.
*/
- queue<CompileResourceWorkItem>& getWorkQueue() {
+ std::queue<CompileResourceWorkItem>& getWorkQueue() {
return mWorkQueue;
}
@@ -587,10 +585,10 @@ private:
size_t mNumLocal;
SourcePos mCurrentXmlPos;
Bundle* mBundle;
-
+
// key = string resource name, value = set of locales in which that name is defined
- map<String16, map<String8, SourcePos> > mLocalizations;
- queue<CompileResourceWorkItem> mWorkQueue;
+ std::map<String16, std::map<String8, SourcePos>> mLocalizations;
+ std::queue<CompileResourceWorkItem> mWorkQueue;
};
#endif
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 2727b3dc9252..a18e9f191941 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -3,23 +3,28 @@
//
// Build resource files from raw assets.
//
-
#include "StringPool.h"
-#include "ResourceTable.h"
#include <utils/ByteOrder.h>
#include <utils/SortedVector.h>
-#include "qsort_r_compat.h"
+#include <algorithm>
+
+#include "ResourceTable.h"
+
+// SSIZE: mingw does not have signed size_t == ssize_t.
#if HAVE_PRINTF_ZD
# define ZD "%zd"
# define ZD_TYPE ssize_t
+# define SSIZE(x) x
#else
# define ZD "%ld"
# define ZD_TYPE long
+# define SSIZE(x) (signed size_t)x
#endif
-#define NOISY(x) //x
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
#if __cplusplus >= 201103L
void strcpy16_htod(char16_t* dst, const char16_t* src)
@@ -152,8 +157,10 @@ ssize_t StringPool::add(const String16& value,
if (configTypeName != NULL) {
entry& ent = mEntries.editItemAt(eidx);
- NOISY(printf("*** adding config type name %s, was %s\n",
- configTypeName->string(), ent.configTypeName.string()));
+ if (kIsDebug) {
+ printf("*** adding config type name %s, was %s\n",
+ configTypeName->string(), ent.configTypeName.string());
+ }
if (ent.configTypeName.size() <= 0) {
ent.configTypeName = *configTypeName;
} else if (ent.configTypeName != *configTypeName) {
@@ -169,14 +176,18 @@ ssize_t StringPool::add(const String16& value,
int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
if (cmp >= 0) {
if (cmp > 0) {
- NOISY(printf("*** inserting config: %s\n", config->toString().string()));
+ if (kIsDebug) {
+ printf("*** inserting config: %s\n", config->toString().string());
+ }
ent.configs.insertAt(*config, addPos);
}
break;
}
}
if (addPos >= ent.configs.size()) {
- NOISY(printf("*** adding config: %s\n", config->toString().string()));
+ if (kIsDebug) {
+ printf("*** adding config: %s\n", config->toString().string());
+ }
ent.configs.add(*config);
}
}
@@ -193,9 +204,11 @@ ssize_t StringPool::add(const String16& value,
ent.indices.add(pos);
}
- NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n",
- String8(value).string(), pos, eidx, vidx));
-
+ if (kIsDebug) {
+ printf("Adding string %s to pool: pos=%zd eidx=%zd vidx=%zd\n",
+ String8(value).string(), SSIZE(pos), SSIZE(eidx), SSIZE(vidx));
+ }
+
return pos;
}
@@ -234,12 +247,15 @@ status_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span)
return NO_ERROR;
}
-int StringPool::config_sort(void* state, const void* lhs, const void* rhs)
+StringPool::ConfigSorter::ConfigSorter(const StringPool& pool) : pool(pool)
+{
+}
+
+bool StringPool::ConfigSorter::operator()(size_t l, size_t r)
{
- StringPool* pool = (StringPool*)state;
- const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]];
- const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]];
- return lhe.compare(rhe);
+ const StringPool::entry& lhe = pool.mEntries[pool.mEntryArray[l]];
+ const StringPool::entry& rhe = pool.mEntries[pool.mEntryArray[r]];
+ return lhe.compare(rhe) < 0;
}
void StringPool::sortByConfig()
@@ -259,12 +275,14 @@ void StringPool::sortByConfig()
}
// Sort the array.
- NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
- // Vector::sort uses insertion sort, which is very slow for this data set.
- // Use quicksort instead because we don't need a stable sort here.
- qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort);
- //newPosToOriginalPos.sort(config_sort, this);
- NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
+ if (kIsDebug) {
+ printf("SORTING STRINGS BY CONFIGURATION...\n");
+ }
+ ConfigSorter sorter(*this);
+ std::sort(newPosToOriginalPos.begin(), newPosToOriginalPos.end(), sorter);
+ if (kIsDebug) {
+ printf("DONE SORTING STRINGS BY CONFIGURATION.\n");
+ }
// Create the reverse mapping from the original position in the array
// to the new position where it appears in the sorted array. This is
@@ -467,9 +485,9 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
strncpy((char*)strings, encStr, encSize+1);
} else {
- uint16_t* strings = (uint16_t*)dat;
+ char16_t* strings = (char16_t*)dat;
- ENCODE_LENGTH(strings, sizeof(uint16_t), strSize)
+ ENCODE_LENGTH(strings, sizeof(char16_t), strSize)
strcpy16_htod(strings, ent.value);
}
@@ -561,9 +579,13 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
for (i=0; i<ENTRIES; i++) {
entry& ent = mEntries.editItemAt(mEntryArray[i]);
*index++ = htodl(ent.offset);
- NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i,
- String8(ent.value).string(),
- mEntryArray[i], ent.offset));
+ if (kIsDebug) {
+ printf("Writing entry #%zu: \"%s\" ent=%zu off=%zu\n",
+ i,
+ String8(ent.value).string(),
+ mEntryArray[i],
+ ent.offset);
+ }
}
// Write style index array.
@@ -579,8 +601,10 @@ ssize_t StringPool::offsetForString(const String16& val) const
{
const Vector<size_t>* indices = offsetsForString(val);
ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
- NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res,
- res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8()));
+ if (kIsDebug) {
+ printf("Offset for string %s: %zd (%s)\n", String8(val).string(), SSIZE(res),
+ res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8());
+ }
return res;
}
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index a9c7becbe700..dbe8c8542185 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -141,7 +141,14 @@ public:
const Vector<size_t>* offsetsForString(const String16& val) const;
private:
- static int config_sort(void* state, const void* lhs, const void* rhs);
+ class ConfigSorter
+ {
+ public:
+ explicit ConfigSorter(const StringPool&);
+ bool operator()(size_t l, size_t r);
+ private:
+ const StringPool& pool;
+ };
const bool mUTF8;
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 899fb63e2a4c..b38b2eda4f73 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -16,8 +16,26 @@
#define O_BINARY 0
#endif
-#define NOISY(x) //x
-#define NOISY_PARSE(x) //x
+// SSIZE: mingw does not have signed size_t == ssize_t.
+// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
+#if HAVE_PRINTF_ZD
+# define SSIZE(x) x
+# define STATUST(x) x
+#else
+# define SSIZE(x) (signed size_t)x
+# define STATUST(x) (status_t)x
+#endif
+
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
+// Set to true for noisy debug output of parsing.
+static const bool kIsDebugParse = false;
+
+#if PRINT_STRING_METRICS
+static const bool kPrintStringMetrics = true;
+#else
+static const bool kPrintStringMetrics = false;
+#endif
const char* const RESOURCES_ROOT_NAMESPACE = "http://schemas.android.com/apk/res/";
const char* const RESOURCES_ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android";
@@ -56,7 +74,10 @@ String16 getNamespaceResourcePackage(String16 appPackage, String16 namespaceUri,
size_t prefixSize;
bool isPublic = true;
if(namespaceUri.startsWith(RESOURCES_PREFIX_AUTO_PACKAGE)) {
- NOISY(printf("Using default application package: %s -> %s\n", String8(namespaceUri).string(), String8(appPackage).string()));
+ if (kIsDebug) {
+ printf("Using default application package: %s -> %s\n", String8(namespaceUri).string(),
+ String8(appPackage).string());
+ }
isPublic = true;
return appPackage;
} else if (namespaceUri.startsWith(RESOURCES_PREFIX)) {
@@ -180,7 +201,7 @@ status_t hasSubstitutionErrors(const char* fileName,
return NO_ERROR;
}
-status_t parseStyledString(Bundle* bundle,
+status_t parseStyledString(Bundle* /* bundle */,
const char* fileName,
ResXMLTree* inXml,
const String16& endTag,
@@ -557,8 +578,10 @@ status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree,
}
root->removeWhitespace(stripAll, cDataTags);
- NOISY(printf("Input XML from %s:\n", (const char*)file->getPrintableSource()));
- NOISY(root->print());
+ if (kIsDebug) {
+ printf("Input XML from %s:\n", (const char*)file->getPrintableSource());
+ root->print();
+ }
sp<AaptFile> rsc = new AaptFile(String8(), AaptGroupEntry(), String8());
status_t err = root->flatten(rsc, !keepComments, false);
if (err != NO_ERROR) {
@@ -569,8 +592,10 @@ status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree,
return err;
}
- NOISY(printf("Output XML:\n"));
- NOISY(printXMLBlock(outTree));
+ if (kIsDebug) {
+ printf("Output XML:\n");
+ printXMLBlock(outTree);
+ }
return NO_ERROR;
}
@@ -850,11 +875,13 @@ void XMLNode::setAttributeResID(size_t attrIdx, uint32_t resId)
} else {
mAttributeOrder.removeItem(e.index);
}
- NOISY(printf("Elem %s %s=\"%s\": set res id = 0x%08x\n",
- String8(getElementName()).string(),
- String8(mAttributes.itemAt(attrIdx).name).string(),
- String8(mAttributes.itemAt(attrIdx).string).string(),
- resId));
+ if (kIsDebug) {
+ printf("Elem %s %s=\"%s\": set res id = 0x%08x\n",
+ String8(getElementName()).string(),
+ String8(mAttributes.itemAt(attrIdx).name).string(),
+ String8(mAttributes.itemAt(attrIdx).string).string(),
+ resId);
+ }
mAttributes.editItemAt(attrIdx).nameResId = resId;
mAttributeOrder.add(resId, attrIdx);
}
@@ -965,9 +992,11 @@ status_t XMLNode::parseValues(const sp<AaptAssets>& assets,
e.nameResId, NULL, &defPackage, table, &ac)) {
hasErrors = true;
}
- NOISY(printf("Attr %s: type=0x%x, str=%s\n",
- String8(e.name).string(), e.value.dataType,
- String8(e.string).string()));
+ if (kIsDebug) {
+ printf("Attr %s: type=0x%x, str=%s\n",
+ String8(e.name).string(), e.value.dataType,
+ String8(e.string).string());
+ }
}
}
const size_t N = mChildren.size();
@@ -977,7 +1006,7 @@ status_t XMLNode::parseValues(const sp<AaptAssets>& assets,
hasErrors = true;
}
}
- return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+ return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets,
@@ -992,15 +1021,17 @@ status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets,
for (size_t i=0; i<N; i++) {
const attribute_entry& e = mAttributes.itemAt(i);
if (e.ns.size() <= 0) continue;
- bool nsIsPublic;
+ bool nsIsPublic = true;
String16 pkg(getNamespaceResourcePackage(String16(assets->getPackage()), e.ns, &nsIsPublic));
- NOISY(printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n",
- String8(getElementName()).string(),
- String8(e.name).string(),
- String8(e.string).string(),
- String8(e.ns).string(),
- (nsIsPublic) ? "public" : "private",
- String8(pkg).string()));
+ if (kIsDebug) {
+ printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n",
+ String8(getElementName()).string(),
+ String8(e.name).string(),
+ String8(e.string).string(),
+ String8(e.ns).string(),
+ (nsIsPublic) ? "public" : "private",
+ String8(pkg).string());
+ }
if (pkg.size() <= 0) continue;
uint32_t res = table != NULL
? table->getResId(e.name, &attr, &pkg, &errorMsg, nsIsPublic)
@@ -1009,8 +1040,10 @@ status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets,
attr.string(), attr.size(),
pkg.string(), pkg.size());
if (res != 0) {
- NOISY(printf("XML attribute name %s: resid=0x%08x\n",
- String8(e.name).string(), res));
+ if (kIsDebug) {
+ printf("XML attribute name %s: resid=0x%08x\n",
+ String8(e.name).string(), res);
+ }
setAttributeResID(i, res);
} else {
SourcePos(mFilename, getStartLineNumber()).error(
@@ -1028,7 +1061,7 @@ status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets,
}
}
- return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+ return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
}
sp<XMLNode> XMLNode::clone() const {
@@ -1070,18 +1103,7 @@ status_t XMLNode::flatten(const sp<AaptFile>& dest,
// Next collect all remainibng strings.
collect_strings(&strings, &resids, stripComments, stripRawValues);
-#if 0 // No longer compiles
- NOISY(printf("Found strings:\n");
- const size_t N = strings.size();
- for (size_t i=0; i<N; i++) {
- printf("%s\n", String8(strings.entryAt(i).string).string());
- }
- );
-#endif
-
sp<AaptFile> stringPool = strings.createStringBlock();
- NOISY(aout << "String pool:"
- << HexDump(stringPool->getData(), stringPool->getSize()) << endl);
ResXMLTree_header header;
memset(&header, 0, sizeof(header));
@@ -1112,17 +1134,13 @@ status_t XMLNode::flatten(const sp<AaptFile>& dest,
void* data = dest->editData();
ResXMLTree_header* hd = (ResXMLTree_header*)(((uint8_t*)data)+basePos);
- size_t size = dest->getSize()-basePos;
hd->header.size = htodl(dest->getSize()-basePos);
- NOISY(aout << "XML resource:"
- << HexDump(dest->getData(), dest->getSize()) << endl);
-
- #if PRINT_STRING_METRICS
- fprintf(stderr, "**** total xml size: %d / %d%% strings (in %s)\n",
- dest->getSize(), (stringPool->getSize()*100)/dest->getSize(),
- dest->getPath().string());
- #endif
+ if (kPrintStringMetrics) {
+ fprintf(stderr, "**** total xml size: %zu / %zu%% strings (in %s)\n",
+ dest->getSize(), (stringPool->getSize()*100)/dest->getSize(),
+ dest->getPath().string());
+ }
return NO_ERROR;
}
@@ -1195,7 +1213,9 @@ static void splitName(const char* name, String16* outNs, String16* outName)
void XMLCALL
XMLNode::startNamespace(void *userData, const char *prefix, const char *uri)
{
- NOISY_PARSE(printf("Start Namespace: %s %s\n", prefix, uri));
+ if (kIsDebugParse) {
+ printf("Start Namespace: %s %s\n", prefix, uri);
+ }
ParseState* st = (ParseState*)userData;
sp<XMLNode> node = XMLNode::newNamespace(st->filename,
String16(prefix != NULL ? prefix : ""), String16(uri));
@@ -1211,7 +1231,9 @@ XMLNode::startNamespace(void *userData, const char *prefix, const char *uri)
void XMLCALL
XMLNode::startElement(void *userData, const char *name, const char **atts)
{
- NOISY_PARSE(printf("Start Element: %s\n", name));
+ if (kIsDebugParse) {
+ printf("Start Element: %s\n", name);
+ }
ParseState* st = (ParseState*)userData;
String16 ns16, name16;
splitName(name, &ns16, &name16);
@@ -1237,7 +1259,9 @@ XMLNode::startElement(void *userData, const char *name, const char **atts)
void XMLCALL
XMLNode::characterData(void *userData, const XML_Char *s, int len)
{
- NOISY_PARSE(printf("CDATA: \"%s\"\n", String8(s, len).string()));
+ if (kIsDebugParse) {
+ printf("CDATA: \"%s\"\n", String8(s, len).string());
+ }
ParseState* st = (ParseState*)userData;
sp<XMLNode> node = NULL;
if (st->stack.size() == 0) {
@@ -1264,7 +1288,9 @@ XMLNode::characterData(void *userData, const XML_Char *s, int len)
void XMLCALL
XMLNode::endElement(void *userData, const char *name)
{
- NOISY_PARSE(printf("End Element: %s\n", name));
+ if (kIsDebugParse) {
+ printf("End Element: %s\n", name);
+ }
ParseState* st = (ParseState*)userData;
sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1);
node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser));
@@ -1284,7 +1310,9 @@ void XMLCALL
XMLNode::endNamespace(void *userData, const char *prefix)
{
const char* nonNullPrefix = prefix != NULL ? prefix : "";
- NOISY_PARSE(printf("End Namespace: %s\n", prefix));
+ if (kIsDebugParse) {
+ printf("End Namespace: %s\n", prefix);
+ }
ParseState* st = (ParseState*)userData;
sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1);
node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser));
@@ -1296,7 +1324,9 @@ XMLNode::endNamespace(void *userData, const char *prefix)
void XMLCALL
XMLNode::commentData(void *userData, const char *comment)
{
- NOISY_PARSE(printf("Comment: %s\n", comment));
+ if (kIsDebugParse) {
+ printf("Comment: %s\n", comment);
+ }
ParseState* st = (ParseState*)userData;
if (st->pendingComment.size() > 0) {
st->pendingComment.append(String16("\n"));
@@ -1393,8 +1423,10 @@ status_t XMLNode::collect_attr_strings(StringPool* outPool,
}
if (idx < 0) {
idx = outPool->add(attr.name);
- NOISY(printf("Adding attr %s (resid 0x%08x) to pool: idx=%d\n",
- String8(attr.name).string(), id, idx));
+ if (kIsDebug) {
+ printf("Adding attr %s (resid 0x%08x) to pool: idx=%zd\n",
+ String8(attr.name).string(), id, SSIZE(idx));
+ }
if (id != 0) {
while ((ssize_t)outResIds->size() <= idx) {
outResIds->add(0);
@@ -1403,8 +1435,9 @@ status_t XMLNode::collect_attr_strings(StringPool* outPool,
}
}
attr.namePoolIdx = idx;
- NOISY(printf("String %s offset=0x%08x\n",
- String8(attr.name).string(), idx));
+ if (kIsDebug) {
+ printf("String %s offset=0x%08zd\n", String8(attr.name).string(), SSIZE(idx));
+ }
}
}
diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp
index b575988f0277..54a8e9c9b247 100644
--- a/tools/aapt/ZipEntry.cpp
+++ b/tools/aapt/ZipEntry.cpp
@@ -141,33 +141,15 @@ void ZipEntry::initNew(const char* fileName, const char* comment)
*
* Initializes the CDE and the LFH.
*/
-status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+status_t ZipEntry::initFromExternal(const ZipFile* /* pZipFile */,
const ZipEntry* pEntry)
{
- /*
- * Copy everything in the CDE over, then fix up the hairy bits.
- */
- memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
-
- if (mCDE.mFileNameLength > 0) {
- mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
- if (mCDE.mFileName == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
- }
- if (mCDE.mFileCommentLength > 0) {
- mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
- if (mCDE.mFileComment == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
- }
- if (mCDE.mExtraFieldLength > 0) {
- /* we null-terminate this, though it may not be a string */
- mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
- if (mCDE.mExtraField == NULL)
- return NO_MEMORY;
- memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
- mCDE.mExtraFieldLength+1);
+ mCDE = pEntry->mCDE;
+ // Check whether we got all the memory needed.
+ if ((mCDE.mFileNameLength > 0 && mCDE.mFileName == NULL) ||
+ (mCDE.mFileCommentLength > 0 && mCDE.mFileComment == NULL) ||
+ (mCDE.mExtraFieldLength > 0 && mCDE.mExtraField == NULL)) {
+ return NO_MEMORY;
}
/* construct the LFH from the CDE */
@@ -356,7 +338,7 @@ time_t ZipEntry::getModWhen(void) const
*/
void ZipEntry::setModWhen(time_t when)
{
-#ifdef HAVE_LOCALTIME_R
+#if !defined(_WIN32)
struct tm tmResult;
#endif
time_t even;
@@ -368,7 +350,7 @@ void ZipEntry::setModWhen(time_t when)
even = (time_t)(((unsigned long)(when) + 1) & (~1));
/* expand */
-#ifdef HAVE_LOCALTIME_R
+#if !defined(_WIN32)
ptm = localtime_r(&even, &tmResult);
#else
ptm = localtime(&even);
@@ -694,3 +676,60 @@ void ZipEntry::CentralDirEntry::dump(void) const
ALOGD(" comment: '%s'\n", mFileComment);
}
+/*
+ * Copy-assignment operator for CentralDirEntry.
+ */
+ZipEntry::CentralDirEntry& ZipEntry::CentralDirEntry::operator=(const ZipEntry::CentralDirEntry& src) {
+ if (this == &src) {
+ return *this;
+ }
+
+ // Free up old data.
+ delete[] mFileName;
+ delete[] mExtraField;
+ delete[] mFileComment;
+
+ // Copy scalars.
+ mVersionMadeBy = src.mVersionMadeBy;
+ mVersionToExtract = src.mVersionToExtract;
+ mGPBitFlag = src.mGPBitFlag;
+ mCompressionMethod = src.mCompressionMethod;
+ mLastModFileTime = src.mLastModFileTime;
+ mLastModFileDate = src.mLastModFileDate;
+ mCRC32 = src.mCRC32;
+ mCompressedSize = src.mCompressedSize;
+ mUncompressedSize = src.mUncompressedSize;
+ mFileNameLength = src.mFileNameLength;
+ mExtraFieldLength = src.mExtraFieldLength;
+ mFileCommentLength = src.mFileCommentLength;
+ mDiskNumberStart = src.mDiskNumberStart;
+ mInternalAttrs = src.mInternalAttrs;
+ mExternalAttrs = src.mExternalAttrs;
+ mLocalHeaderRelOffset = src.mLocalHeaderRelOffset;
+
+ // Copy strings, if necessary.
+ if (mFileNameLength > 0) {
+ mFileName = new unsigned char[mFileNameLength + 1];
+ if (mFileName != NULL)
+ strcpy((char*)mFileName, (char*)src.mFileName);
+ } else {
+ mFileName = NULL;
+ }
+ if (mFileCommentLength > 0) {
+ mFileComment = new unsigned char[mFileCommentLength + 1];
+ if (mFileComment != NULL)
+ strcpy((char*)mFileComment, (char*)src.mFileComment);
+ } else {
+ mFileComment = NULL;
+ }
+ if (mExtraFieldLength > 0) {
+ /* we null-terminate this, though it may not be a string */
+ mExtraField = new unsigned char[mExtraFieldLength + 1];
+ if (mExtraField != NULL)
+ memcpy(mExtraField, src.mExtraField, mExtraFieldLength + 1);
+ } else {
+ mExtraField = NULL;
+ }
+
+ return *this;
+}
diff --git a/tools/aapt/ZipEntry.h b/tools/aapt/ZipEntry.h
index c2f3227cf230..287a540673a3 100644
--- a/tools/aapt/ZipEntry.h
+++ b/tools/aapt/ZipEntry.h
@@ -298,6 +298,8 @@ private:
status_t read(FILE* fp);
status_t write(FILE* fp);
+ CentralDirEntry& operator=(const CentralDirEntry& src);
+
// unsigned long mSignature;
unsigned short mVersionMadeBy;
unsigned short mVersionToExtract;
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 8057068dd685..36f4e73b3ac2 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -676,8 +676,6 @@ status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
status_t ZipFile::copyDataToFp(FILE* dstFp,
const void* data, size_t size, unsigned long* pCRC32)
{
- size_t count;
-
*pCRC32 = crc32(0L, Z_NULL, 0);
if (size > 0) {
*pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
diff --git a/tools/aapt/qsort_r_compat.c b/tools/aapt/qsort_r_compat.c
deleted file mode 100644
index 2a8dbe85f4c9..000000000000
--- a/tools/aapt/qsort_r_compat.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2012 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 <stdlib.h>
-#include "qsort_r_compat.h"
-
-/*
- * Note: This code is only used on the host, and is primarily here for
- * Mac OS compatibility. Apparently, glibc and Apple's libc disagree on
- * the parameter order for qsort_r.
- */
-
-#if HAVE_BSD_QSORT_R
-
-/*
- * BSD qsort_r parameter order is as we have defined here.
- */
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
- int (*compar)(void*, const void* , const void*)) {
- qsort_r(base, nel, width, thunk, compar);
-}
-
-#elif HAVE_GNU_QSORT_R
-
-/*
- * GNU qsort_r parameter order places the thunk parameter last.
- */
-
-struct compar_data {
- void* thunk;
- int (*compar)(void*, const void* , const void*);
-};
-
-static int compar_wrapper(const void* a, const void* b, void* data) {
- struct compar_data* compar_data = (struct compar_data*)data;
- return compar_data->compar(compar_data->thunk, a, b);
-}
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
- int (*compar)(void*, const void* , const void*)) {
- struct compar_data compar_data;
- compar_data.thunk = thunk;
- compar_data.compar = compar;
- qsort_r(base, nel, width, compar_wrapper, &compar_data);
-}
-
-#else
-
-/*
- * Emulate qsort_r using thread local storage to access the thunk data.
- */
-
-#include <cutils/threads.h>
-
-static thread_store_t compar_data_key = THREAD_STORE_INITIALIZER;
-
-struct compar_data {
- void* thunk;
- int (*compar)(void*, const void* , const void*);
-};
-
-static int compar_wrapper(const void* a, const void* b) {
- struct compar_data* compar_data = (struct compar_data*)thread_store_get(&compar_data_key);
- return compar_data->compar(compar_data->thunk, a, b);
-}
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
- int (*compar)(void*, const void* , const void*)) {
- struct compar_data compar_data;
- compar_data.thunk = thunk;
- compar_data.compar = compar;
- thread_store_set(&compar_data_key, &compar_data, NULL);
- qsort(base, nel, width, compar_wrapper);
-}
-
-#endif
diff --git a/tools/aapt/qsort_r_compat.h b/tools/aapt/qsort_r_compat.h
deleted file mode 100644
index e14f999f736a..000000000000
--- a/tools/aapt/qsort_r_compat.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/*
- * Provides a portable version of qsort_r, called qsort_r_compat, which is a
- * reentrant variant of qsort that passes a user data pointer to its comparator.
- * This implementation follows the BSD parameter convention.
- */
-
-#ifndef ___QSORT_R_COMPAT_H
-#define ___QSORT_R_COMPAT_H
-
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
- int (*compar)(void*, const void* , const void* ));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ___QSORT_R_COMPAT_H
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
index e795d81836bd..ef3860c72921 100644
--- a/tools/aapt/tests/AaptConfig_test.cpp
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -76,3 +76,9 @@ TEST(AaptConfigTest, ParseQualifierAddedInApi13) {
EXPECT_TRUE(TestParse("sw600dp-v8", &config));
EXPECT_EQ(String8("sw600dp-v13"), config.toString());
}
+
+TEST(AaptConfigTest, TestParsingOfCarAttribute) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("car", &config));
+ EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_CAR, config.uiMode);
+}
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 45dd23b911e3..14c9f95a247b 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -228,7 +228,8 @@ check_filename(const char* filename, const char* package, buffer_type* name)
}
#endif
-#ifdef OS_CASE_SENSITIVE
+ // aidl assumes case-insensitivity on Mac Os and Windows.
+#if defined(__linux__)
valid = (expected == p);
#else
valid = !strcasecmp(expected.c_str(), p);
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 393d2ec5d012..5c6d870f653d 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -48,8 +48,9 @@ def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
class Field():
- def __init__(self, clazz, raw, blame):
+ def __init__(self, clazz, line, raw, blame):
self.clazz = clazz
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
@@ -73,8 +74,9 @@ class Field():
class Method():
- def __init__(self, clazz, raw, blame):
+ def __init__(self, clazz, line, raw, blame):
self.clazz = clazz
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
@@ -110,8 +112,9 @@ class Method():
class Class():
- def __init__(self, pkg, raw, blame):
+ def __init__(self, pkg, line, raw, blame):
self.pkg = pkg
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
self.ctors = []
@@ -129,10 +132,14 @@ class Class():
if "extends" in raw:
self.extends = raw[raw.index("extends")+1]
+ self.extends_path = self.extends.split(".")
else:
self.extends = None
+ self.extends_path = []
self.fullname = self.pkg.name + "." + self.fullname
+ self.fullname_path = self.fullname.split(".")
+
self.name = self.fullname[self.fullname.rindex(".")+1:]
def __repr__(self):
@@ -140,75 +147,110 @@ class Class():
class Package():
- def __init__(self, raw, blame):
+ def __init__(self, line, raw, blame):
+ self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
raw = raw.split()
self.name = raw[raw.index("package")+1]
+ self.name_path = self.name.split(".")
def __repr__(self):
return self.raw
-def parse_api(fn):
+def _parse_stream(f, clazz_cb=None):
+ line = 0
api = {}
pkg = None
clazz = None
blame = None
re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
-
- with open(fn) as f:
- for raw in f.readlines():
- raw = raw.rstrip()
- match = re_blame.match(raw)
- if match is not None:
- blame = match.groups()[0:2]
- raw = match.groups()[2]
- else:
- blame = None
-
- if raw.startswith("package"):
- pkg = Package(raw, blame)
- elif raw.startswith(" ") and raw.endswith("{"):
- clazz = Class(pkg, raw, blame)
+ for raw in f:
+ line += 1
+ raw = raw.rstrip()
+ match = re_blame.match(raw)
+ if match is not None:
+ blame = match.groups()[0:2]
+ raw = match.groups()[2]
+ else:
+ blame = None
+
+ if raw.startswith("package"):
+ pkg = Package(line, raw, blame)
+ elif raw.startswith(" ") and raw.endswith("{"):
+ # When provided with class callback, we treat as incremental
+ # parse and don't build up entire API
+ if clazz and clazz_cb:
+ clazz_cb(clazz)
+ clazz = Class(pkg, line, raw, blame)
+ if not clazz_cb:
api[clazz.fullname] = clazz
- elif raw.startswith(" ctor"):
- clazz.ctors.append(Method(clazz, raw, blame))
- elif raw.startswith(" method"):
- clazz.methods.append(Method(clazz, raw, blame))
- elif raw.startswith(" field"):
- clazz.fields.append(Field(clazz, raw, blame))
+ elif raw.startswith(" ctor"):
+ clazz.ctors.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" method"):
+ clazz.methods.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" field"):
+ clazz.fields.append(Field(clazz, line, raw, blame))
+
+ # Handle last trailing class
+ if clazz and clazz_cb:
+ clazz_cb(clazz)
return api
+class Failure():
+ def __init__(self, sig, clazz, detail, error, rule, msg):
+ self.sig = sig
+ self.error = error
+ self.rule = rule
+ self.msg = msg
+
+ if error:
+ self.head = "Error %s" % (rule) if rule else "Error"
+ dump = "%s%s:%s %s" % (format(fg=RED, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+ else:
+ self.head = "Warning %s" % (rule) if rule else "Warning"
+ dump = "%s%s:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+
+ self.line = clazz.line
+ blame = clazz.blame
+ if detail is not None:
+ dump += "\n in " + repr(detail)
+ self.line = detail.line
+ blame = detail.blame
+ dump += "\n in " + repr(clazz)
+ dump += "\n in " + repr(clazz.pkg)
+ dump += "\n at line " + repr(self.line)
+ if blame is not None:
+ dump += "\n last modified by %s in %s" % (blame[1], blame[0])
+
+ self.dump = dump
+
+ def __repr__(self):
+ return self.dump
+
+
failures = {}
-def _fail(clazz, detail, msg):
+def _fail(clazz, detail, error, rule, msg):
"""Records an API failure to be processed later."""
global failures
sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg)
sig = sig.replace(" deprecated ", " ")
- res = msg
- blame = clazz.blame
- if detail is not None:
- res += "\n in " + repr(detail)
- blame = detail.blame
- res += "\n in " + repr(clazz)
- res += "\n in " + repr(clazz.pkg)
- if blame is not None:
- res += "\n last modified by %s in %s" % (blame[1], blame[0])
- failures[sig] = res
+ failures[sig] = Failure(sig, clazz, detail, error, rule, msg)
+
-def warn(clazz, detail, msg):
- _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg))
+def warn(clazz, detail, rule, msg):
+ _fail(clazz, detail, False, rule, msg)
-def error(clazz, detail, msg):
- _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg))
+def error(clazz, detail, rule, msg):
+ _fail(clazz, detail, True, rule, msg)
def verify_constants(clazz):
@@ -218,13 +260,13 @@ def verify_constants(clazz):
for f in clazz.fields:
if "static" in f.split and "final" in f.split:
if re.match("[A-Z0-9_]+", f.name) is None:
- error(clazz, f, "Constant field names should be FOO_NAME")
+ error(clazz, f, "C2", "Constant field names must be FOO_NAME")
def verify_enums(clazz):
"""Enums are bad, mmkay?"""
if "extends java.lang.Enum" in clazz.raw:
- error(clazz, None, "Enums are not allowed")
+ error(clazz, None, "F5", "Enums are not allowed")
def verify_class_names(clazz):
@@ -234,9 +276,9 @@ def verify_class_names(clazz):
if re.match("android\.R\.[a-z]+", clazz.fullname): return
if re.search("[A-Z]{2,}", clazz.name) is not None:
- warn(clazz, None, "Class name style should be Mtp not MTP")
+ warn(clazz, None, "S1", "Class names with acronyms should be Mtp not MTP")
if re.match("[^A-Z]", clazz.name):
- error(clazz, None, "Class must start with uppercase char")
+ error(clazz, None, "S1", "Class must start with uppercase char")
def verify_method_names(clazz):
@@ -247,9 +289,9 @@ def verify_method_names(clazz):
for m in clazz.methods:
if re.search("[A-Z]{2,}", m.name) is not None:
- warn(clazz, m, "Method name style should be getMtu() instead of getMTU()")
+ warn(clazz, m, "S1", "Method names with acronyms should be getMtu() instead of getMTU()")
if re.match("[^a-z]", m.name):
- error(clazz, m, "Method name must start with lowercase char")
+ error(clazz, m, "S1", "Method name must start with lowercase char")
def verify_callbacks(clazz):
@@ -259,17 +301,17 @@ def verify_callbacks(clazz):
if clazz.fullname == "android.speech.tts.SynthesisCallback": return
if clazz.name.endswith("Callbacks"):
- error(clazz, None, "Class name must not be plural")
+ error(clazz, None, "L1", "Callback class names should be singular")
if clazz.name.endswith("Observer"):
- warn(clazz, None, "Class should be named FooCallback")
+ warn(clazz, None, "L1", "Class should be named FooCallback")
if clazz.name.endswith("Callback"):
if "interface" in clazz.split:
- error(clazz, None, "Callback must be abstract class to enable extension in future API levels")
+ error(clazz, None, "CL3", "Callbacks must be abstract class to enable extension in future API levels")
for m in clazz.methods:
if not re.match("on[A-Z][a-z]*", m.name):
- error(clazz, m, "Callback method names must be onFoo() style")
+ error(clazz, m, "L1", "Callback method names must be onFoo() style")
def verify_listeners(clazz):
@@ -281,16 +323,16 @@ def verify_listeners(clazz):
if clazz.name.endswith("Listener"):
if " abstract class " in clazz.raw:
- error(clazz, None, "Listener should be an interface, otherwise renamed Callback")
+ error(clazz, None, "L1", "Listeners should be an interface, or otherwise renamed Callback")
for m in clazz.methods:
if not re.match("on[A-Z][a-z]*", m.name):
- error(clazz, m, "Listener method names must be onFoo() style")
+ error(clazz, m, "L1", "Listener method names must be onFoo() style")
if len(clazz.methods) == 1 and clazz.name.startswith("On"):
m = clazz.methods[0]
if (m.name + "Listener").lower() != clazz.name.lower():
- error(clazz, m, "Single listener method name should match class name")
+ error(clazz, m, "L1", "Single listener method name must match class name")
def verify_actions(clazz):
@@ -308,7 +350,7 @@ def verify_actions(clazz):
if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
if "_ACTION" in f.name or "ACTION_" in f.name or ".action." in f.value.lower():
if not f.name.startswith("ACTION_"):
- error(clazz, f, "Intent action constant name must be ACTION_FOO")
+ error(clazz, f, "C3", "Intent action constant name must be ACTION_FOO")
else:
if clazz.fullname == "android.content.Intent":
prefix = "android.intent.action"
@@ -320,7 +362,7 @@ def verify_actions(clazz):
prefix = clazz.pkg.name + ".action"
expected = prefix + "." + f.name[7:]
if f.value != expected:
- error(clazz, f, "Inconsistent action value; expected %s" % (expected))
+ error(clazz, f, "C4", "Inconsistent action value; expected %s" % (expected))
def verify_extras(clazz):
@@ -340,7 +382,7 @@ def verify_extras(clazz):
if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
if "_EXTRA" in f.name or "EXTRA_" in f.name or ".extra" in f.value.lower():
if not f.name.startswith("EXTRA_"):
- error(clazz, f, "Intent extra must be EXTRA_FOO")
+ error(clazz, f, "C3", "Intent extra must be EXTRA_FOO")
else:
if clazz.pkg.name == "android.content" and clazz.name == "Intent":
prefix = "android.intent.extra"
@@ -350,7 +392,7 @@ def verify_extras(clazz):
prefix = clazz.pkg.name + ".extra"
expected = prefix + "." + f.name[6:]
if f.value != expected:
- error(clazz, f, "Inconsistent extra value; expected %s" % (expected))
+ error(clazz, f, "C4", "Inconsistent extra value; expected %s" % (expected))
def verify_equals(clazz):
@@ -359,7 +401,7 @@ def verify_equals(clazz):
eq = "equals" in methods
hc = "hashCode" in methods
if eq != hc:
- error(clazz, None, "Must override both equals and hashCode; missing one")
+ error(clazz, None, "M8", "Must override both equals and hashCode; missing one")
def verify_parcelable(clazz):
@@ -370,17 +412,17 @@ def verify_parcelable(clazz):
describe = [ i for i in clazz.methods if i.name == "describeContents" ]
if len(creator) == 0 or len(write) == 0 or len(describe) == 0:
- error(clazz, None, "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
+ error(clazz, None, "FW3", "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
def verify_protected(clazz):
- """Verify that no protected methods are allowed."""
+ """Verify that no protected methods or fields are allowed."""
for m in clazz.methods:
if "protected" in m.split:
- error(clazz, m, "No protected methods; must be public")
+ error(clazz, m, "M7", "Protected methods not allowed; must be public")
for f in clazz.fields:
if "protected" in f.split:
- error(clazz, f, "No protected fields; must be public")
+ error(clazz, f, "M7", "Protected fields not allowed; must be public")
def verify_fields(clazz):
@@ -410,18 +452,18 @@ def verify_fields(clazz):
elif clazz.fullname.startswith("android.util.Mutable"):
pass
else:
- error(clazz, f, "Bare fields must be marked final; consider adding accessors")
+ error(clazz, f, "F2", "Bare fields must be marked final, or add accessors if mutable")
if not "static" in f.split:
if not re.match("[a-z]([a-zA-Z]+)?", f.name):
- error(clazz, f, "Non-static fields must be named with myField style")
+ error(clazz, f, "S1", "Non-static fields must be named using myField style")
if re.match("[ms][A-Z]", f.name):
- error(clazz, f, "Don't expose your internal objects")
+ error(clazz, f, "F1", "Internal objects must not be exposed")
if re.match("[A-Z_]+", f.name):
if "static" not in f.split or "final" not in f.split:
- error(clazz, f, "Constants must be marked static final")
+ error(clazz, f, "C2", "Constants must be marked static final")
def verify_register(clazz):
@@ -434,34 +476,34 @@ def verify_register(clazz):
if m.name.startswith("register"):
other = "unregister" + m.name[8:]
if other not in methods:
- error(clazz, m, "Missing unregister method")
+ error(clazz, m, "L2", "Missing unregister method")
if m.name.startswith("unregister"):
other = "register" + m.name[10:]
if other not in methods:
- error(clazz, m, "Missing register method")
+ error(clazz, m, "L2", "Missing register method")
if m.name.startswith("add") or m.name.startswith("remove"):
- error(clazz, m, "Callback methods should be named register/unregister")
+ error(clazz, m, "L3", "Callback methods should be named register/unregister")
if "Listener" in m.raw:
if m.name.startswith("add"):
other = "remove" + m.name[3:]
if other not in methods:
- error(clazz, m, "Missing remove method")
+ error(clazz, m, "L2", "Missing remove method")
if m.name.startswith("remove") and not m.name.startswith("removeAll"):
other = "add" + m.name[6:]
if other not in methods:
- error(clazz, m, "Missing add method")
+ error(clazz, m, "L2", "Missing add method")
if m.name.startswith("register") or m.name.startswith("unregister"):
- error(clazz, m, "Listener methods should be named add/remove")
+ error(clazz, m, "L3", "Listener methods should be named add/remove")
def verify_sync(clazz):
"""Verify synchronized methods aren't exposed."""
for m in clazz.methods:
if "synchronized" in m.split:
- error(clazz, m, "Internal lock exposed")
+ error(clazz, m, "M5", "Internal locks must not be exposed")
def verify_intent_builder(clazz):
@@ -473,7 +515,7 @@ def verify_intent_builder(clazz):
if m.name.startswith("create") and m.name.endswith("Intent"):
pass
else:
- error(clazz, m, "Methods creating an Intent should be named createFooIntent()")
+ error(clazz, m, "FW1", "Methods creating an Intent must be named createFooIntent()")
def verify_helper_classes(clazz):
@@ -483,57 +525,45 @@ def verify_helper_classes(clazz):
if "extends android.app.Service" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Service"):
- error(clazz, None, "Inconsistent class name; should be FooService")
+ error(clazz, None, "CL4", "Inconsistent class name; should be FooService")
found = False
for f in clazz.fields:
if f.name == "SERVICE_INTERFACE":
found = True
if f.value != clazz.fullname:
- error(clazz, f, "Inconsistent interface constant; expected %s" % (clazz.fullname))
-
- if not found:
- warn(clazz, None, "Missing SERVICE_INTERFACE constant")
-
- if "abstract" in clazz.split and not clazz.fullname.startswith("android.service."):
- warn(clazz, None, "Services extended by developers should be under android.service")
+ error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
if "extends android.content.ContentProvider" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Provider"):
- error(clazz, None, "Inconsistent class name; should be FooProvider")
+ error(clazz, None, "CL4", "Inconsistent class name; should be FooProvider")
found = False
for f in clazz.fields:
if f.name == "PROVIDER_INTERFACE":
found = True
if f.value != clazz.fullname:
- error(clazz, f, "Inconsistent interface name; expected %s" % (clazz.fullname))
-
- if not found:
- warn(clazz, None, "Missing PROVIDER_INTERFACE constant")
-
- if "abstract" in clazz.split and not clazz.fullname.startswith("android.provider."):
- warn(clazz, None, "Providers extended by developers should be under android.provider")
+ error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
if "extends android.content.BroadcastReceiver" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Receiver"):
- error(clazz, None, "Inconsistent class name; should be FooReceiver")
+ error(clazz, None, "CL4", "Inconsistent class name; should be FooReceiver")
if "extends android.app.Activity" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Activity"):
- error(clazz, None, "Inconsistent class name; should be FooActivity")
+ error(clazz, None, "CL4", "Inconsistent class name; should be FooActivity")
if test_methods:
for m in clazz.methods:
if "final" in m.split: continue
if not re.match("on[A-Z]", m.name):
if "abstract" in m.split:
- error(clazz, m, "Methods implemented by developers must be named onFoo()")
+ warn(clazz, m, None, "Methods implemented by developers should be named onFoo()")
else:
- warn(clazz, m, "If implemented by developer, should be named onFoo(); otherwise consider marking final")
+ warn(clazz, m, None, "If implemented by developer, should be named onFoo(); otherwise consider marking final")
def verify_builder(clazz):
@@ -543,7 +573,7 @@ def verify_builder(clazz):
if not clazz.name.endswith("Builder"): return
if clazz.name != "Builder":
- warn(clazz, None, "Builder should be defined as inner class")
+ warn(clazz, None, None, "Builder should be defined as inner class")
has_build = False
for m in clazz.methods:
@@ -555,26 +585,26 @@ def verify_builder(clazz):
if m.name.startswith("clear"): continue
if m.name.startswith("with"):
- error(clazz, m, "Builder methods names must follow setFoo() style")
+ warn(clazz, m, None, "Builder methods names should use setFoo() style")
if m.name.startswith("set"):
if not m.typ.endswith(clazz.fullname):
- warn(clazz, m, "Methods should return the builder")
+ warn(clazz, m, "M4", "Methods must return the builder object")
if not has_build:
- warn(clazz, None, "Missing build() method")
+ warn(clazz, None, None, "Missing build() method")
def verify_aidl(clazz):
"""Catch people exposing raw AIDL."""
if "extends android.os.Binder" in clazz.raw or "implements android.os.IInterface" in clazz.raw:
- error(clazz, None, "Exposing raw AIDL interface")
+ error(clazz, None, None, "Raw AIDL interfaces must not be exposed")
def verify_internal(clazz):
"""Catch people exposing internal classes."""
if clazz.pkg.name.startswith("com.android"):
- error(clazz, None, "Exposing internal class")
+ error(clazz, None, None, "Internal classes must not be exposed")
def verify_layering(clazz):
@@ -609,38 +639,56 @@ def verify_layering(clazz):
for f in clazz.fields:
ir = rank(f.typ)
if ir and ir < cr:
- warn(clazz, f, "Field type violates package layering")
+ warn(clazz, f, "FW6", "Field type violates package layering")
for m in clazz.methods:
ir = rank(m.typ)
if ir and ir < cr:
- warn(clazz, m, "Method return type violates package layering")
+ warn(clazz, m, "FW6", "Method return type violates package layering")
for arg in m.args:
ir = rank(arg)
if ir and ir < cr:
- warn(clazz, m, "Method argument type violates package layering")
+ warn(clazz, m, "FW6", "Method argument type violates package layering")
-def verify_boolean(clazz, api):
- """Catches people returning boolean from getFoo() style methods.
- Ignores when matching setFoo() is present."""
+def verify_boolean(clazz):
+ """Verifies that boolean accessors are named correctly.
+ For example, hasFoo() and setHasFoo()."""
- methods = [ m.name for m in clazz.methods ]
+ def is_get(m): return len(m.args) == 0 and m.typ == "boolean"
+ def is_set(m): return len(m.args) == 1 and m.args[0] == "boolean"
+
+ gets = [ m for m in clazz.methods if is_get(m) ]
+ sets = [ m for m in clazz.methods if is_set(m) ]
- builder = clazz.fullname + ".Builder"
- builder_methods = []
- if builder in api:
- builder_methods = [ m.name for m in api[builder].methods ]
+ def error_if_exists(methods, trigger, expected, actual):
+ for m in methods:
+ if m.name == actual:
+ error(clazz, m, "M6", "Symmetric method for %s must be named %s" % (trigger, expected))
for m in clazz.methods:
- if m.typ == "boolean" and m.name.startswith("get") and m.name != "get" and len(m.args) == 0:
- setter = "set" + m.name[3:]
- if setter in methods:
- pass
- elif builder is not None and setter in builder_methods:
- pass
- else:
- warn(clazz, m, "Methods returning boolean should be named isFoo, hasFoo, areFoo")
+ if is_get(m):
+ if re.match("is[A-Z]", m.name):
+ target = m.name[2:]
+ expected = "setIs" + target
+ error_if_exists(sets, m.name, expected, "setHas" + target)
+ elif re.match("has[A-Z]", m.name):
+ target = m.name[3:]
+ expected = "setHas" + target
+ error_if_exists(sets, m.name, expected, "setIs" + target)
+ error_if_exists(sets, m.name, expected, "set" + target)
+ elif re.match("get[A-Z]", m.name):
+ target = m.name[3:]
+ expected = "set" + target
+ error_if_exists(sets, m.name, expected, "setIs" + target)
+ error_if_exists(sets, m.name, expected, "setHas" + target)
+
+ if is_set(m):
+ if re.match("set[A-Z]", m.name):
+ target = m.name[3:]
+ expected = "get" + target
+ error_if_exists(sets, m.name, expected, "is" + target)
+ error_if_exists(sets, m.name, expected, "has" + target)
def verify_collections(clazz):
@@ -651,10 +699,10 @@ def verify_collections(clazz):
"java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"]
for m in clazz.methods:
if m.typ in bad:
- error(clazz, m, "Return type is concrete collection; should be interface")
+ error(clazz, m, "CL2", "Return type is concrete collection; must be higher-level interface")
for arg in m.args:
if arg in bad:
- error(clazz, m, "Argument is concrete collection; should be interface")
+ error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface")
def verify_flags(clazz):
@@ -669,49 +717,291 @@ def verify_flags(clazz):
scope = f.name[0:f.name.index("FLAG_")]
if val & known[scope]:
- warn(clazz, f, "Found overlapping flag constant value")
+ warn(clazz, f, "C1", "Found overlapping flag constant value")
known[scope] |= val
-def verify_style(api):
- """Find all style issues in the given API level."""
+def verify_exception(clazz):
+ """Verifies that methods don't throw generic exceptions."""
+ for m in clazz.methods:
+ if "throws java.lang.Exception" in m.raw or "throws java.lang.Throwable" in m.raw or "throws java.lang.Error" in m.raw:
+ error(clazz, m, "S1", "Methods must not throw generic exceptions")
+
+
+def verify_google(clazz):
+ """Verifies that APIs never reference Google."""
+
+ if re.search("google", clazz.raw, re.IGNORECASE):
+ error(clazz, None, None, "Must never reference Google")
+
+ test = []
+ test.extend(clazz.ctors)
+ test.extend(clazz.fields)
+ test.extend(clazz.methods)
+
+ for t in test:
+ if re.search("google", t.raw, re.IGNORECASE):
+ error(clazz, t, None, "Must never reference Google")
+
+
+def verify_bitset(clazz):
+ """Verifies that we avoid using heavy BitSet."""
+
+ for f in clazz.fields:
+ if f.typ == "java.util.BitSet":
+ error(clazz, f, None, "Field type must not be heavy BitSet")
+
+ for m in clazz.methods:
+ if m.typ == "java.util.BitSet":
+ error(clazz, m, None, "Return type must not be heavy BitSet")
+ for arg in m.args:
+ if arg == "java.util.BitSet":
+ error(clazz, m, None, "Argument type must not be heavy BitSet")
+
+
+def verify_manager(clazz):
+ """Verifies that FooManager is only obtained from Context."""
+
+ if not clazz.name.endswith("Manager"): return
+
+ for c in clazz.ctors:
+ error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
+
+
+def verify_boxed(clazz):
+ """Verifies that methods avoid boxed primitives."""
+
+ boxed = ["java.lang.Number","java.lang.Byte","java.lang.Double","java.lang.Float","java.lang.Integer","java.lang.Long","java.lang.Short"]
+
+ for c in clazz.ctors:
+ for arg in c.args:
+ if arg in boxed:
+ error(clazz, c, "M11", "Must avoid boxed primitives")
+
+ for f in clazz.fields:
+ if f.typ in boxed:
+ error(clazz, f, "M11", "Must avoid boxed primitives")
+
+ for m in clazz.methods:
+ if m.typ in boxed:
+ error(clazz, m, "M11", "Must avoid boxed primitives")
+ for arg in m.args:
+ if arg in boxed:
+ error(clazz, m, "M11", "Must avoid boxed primitives")
+
+
+def verify_static_utils(clazz):
+ """Verifies that helper classes can't be constructed."""
+ if clazz.fullname.startswith("android.opengl"): return
+ if re.match("android\.R\.[a-z]+", clazz.fullname): return
+
+ if len(clazz.fields) > 0: return
+ if len(clazz.methods) == 0: return
+
+ for m in clazz.methods:
+ if "static" not in m.split:
+ return
+
+ # At this point, we have no fields, and all methods are static
+ if len(clazz.ctors) > 0:
+ error(clazz, None, None, "Fully-static utility classes must not have constructor")
+
+
+def verify_overload_args(clazz):
+ """Verifies that method overloads add new arguments at the end."""
+ if clazz.fullname.startswith("android.opengl"): return
+
+ overloads = collections.defaultdict(list)
+ for m in clazz.methods:
+ if "deprecated" in m.split: continue
+ overloads[m.name].append(m)
+
+ for name, methods in overloads.items():
+ if len(methods) <= 1: continue
+
+ # Look for arguments common across all overloads
+ def cluster(args):
+ count = collections.defaultdict(int)
+ res = set()
+ for i in range(len(args)):
+ a = args[i]
+ res.add("%s#%d" % (a, count[a]))
+ count[a] += 1
+ return res
+
+ common_args = cluster(methods[0].args)
+ for m in methods:
+ common_args = common_args & cluster(m.args)
+
+ if len(common_args) == 0: continue
+
+ # Require that all common arguments are present at start of signature
+ locked_sig = None
+ for m in methods:
+ sig = m.args[0:len(common_args)]
+ if not common_args.issubset(cluster(sig)):
+ warn(clazz, m, "M2", "Expected common arguments [%s] at beginning of overloaded method" % (", ".join(common_args)))
+ elif not locked_sig:
+ locked_sig = sig
+ elif locked_sig != sig:
+ error(clazz, m, "M2", "Expected consistent argument ordering between overloads: %s..." % (", ".join(locked_sig)))
+
+
+def verify_callback_handlers(clazz):
+ """Verifies that methods adding listener/callback have overload
+ for specifying delivery thread."""
+
+ # Ignore UI packages which assume main thread
+ skip = [
+ "animation",
+ "view",
+ "graphics",
+ "transition",
+ "widget",
+ "webkit",
+ ]
+ for s in skip:
+ if s in clazz.pkg.name_path: return
+ if s in clazz.extends_path: return
+
+ # Ignore UI classes which assume main thread
+ if "app" in clazz.pkg.name_path or "app" in clazz.extends_path:
+ for s in ["ActionBar","Dialog","Application","Activity","Fragment","Loader"]:
+ if s in clazz.fullname: return
+ if "content" in clazz.pkg.name_path or "content" in clazz.extends_path:
+ for s in ["Loader"]:
+ if s in clazz.fullname: return
+
+ found = {}
+ by_name = collections.defaultdict(list)
+ for m in clazz.methods:
+ if m.name.startswith("unregister"): continue
+ if m.name.startswith("remove"): continue
+ if re.match("on[A-Z]+", m.name): continue
+
+ by_name[m.name].append(m)
+
+ for a in m.args:
+ if a.endswith("Listener") or a.endswith("Callback") or a.endswith("Callbacks"):
+ found[m.name] = m
+
+ for f in found.values():
+ takes_handler = False
+ for m in by_name[f.name]:
+ if "android.os.Handler" in m.args:
+ takes_handler = True
+ if not takes_handler:
+ warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler")
+
+
+def verify_context_first(clazz):
+ """Verifies that methods accepting a Context keep it the first argument."""
+ examine = clazz.ctors + clazz.methods
+ for m in examine:
+ if len(m.args) > 1 and m.args[0] != "android.content.Context":
+ if "android.content.Context" in m.args[1:]:
+ error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
+
+
+def verify_listener_last(clazz):
+ """Verifies that methods accepting a Listener or Callback keep them as last arguments."""
+ examine = clazz.ctors + clazz.methods
+ for m in examine:
+ if "Listener" in m.name or "Callback" in m.name: continue
+ found = False
+ for a in m.args:
+ if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"):
+ found = True
+ elif found and a != "android.os.Handler":
+ warn(clazz, m, "M3", "Listeners should always be at end of argument list")
+
+
+def verify_resource_names(clazz):
+ """Verifies that resource names have consistent case."""
+ if not re.match("android\.R\.[a-z]+", clazz.fullname): return
+
+ # Resources defined by files are foo_bar_baz
+ if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]:
+ for f in clazz.fields:
+ if re.match("[a-z1-9_]+$", f.name): continue
+ error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style")
+
+ # Resources defined inside files are fooBarBaz
+ if clazz.name in ["array","attr","id","bool","fraction","integer"]:
+ for f in clazz.fields:
+ if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue
+ if re.match("layout_[a-z][a-zA-Z1-9]*$", f.name): continue
+ if re.match("state_[a-z_]*$", f.name): continue
+
+ if re.match("[a-z][a-zA-Z1-9]*$", f.name): continue
+ error(clazz, f, "C7", "Expected resource name in this class to be fooBarBaz style")
+
+ # Styles are FooBar_Baz
+ if clazz.name in ["style"]:
+ for f in clazz.fields:
+ if re.match("[A-Z][A-Za-z1-9]+(_[A-Z][A-Za-z1-9]+?)*$", f.name): continue
+ error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
+
+
+def examine_clazz(clazz):
+ """Find all style issues in the given class."""
+ if clazz.pkg.name.startswith("java"): return
+ if clazz.pkg.name.startswith("junit"): return
+ if clazz.pkg.name.startswith("org.apache"): return
+ if clazz.pkg.name.startswith("org.xml"): return
+ if clazz.pkg.name.startswith("org.json"): return
+ if clazz.pkg.name.startswith("org.w3c"): return
+
+ verify_constants(clazz)
+ verify_enums(clazz)
+ verify_class_names(clazz)
+ verify_method_names(clazz)
+ verify_callbacks(clazz)
+ verify_listeners(clazz)
+ verify_actions(clazz)
+ verify_extras(clazz)
+ verify_equals(clazz)
+ verify_parcelable(clazz)
+ verify_protected(clazz)
+ verify_fields(clazz)
+ verify_register(clazz)
+ verify_sync(clazz)
+ verify_intent_builder(clazz)
+ verify_helper_classes(clazz)
+ verify_builder(clazz)
+ verify_aidl(clazz)
+ verify_internal(clazz)
+ verify_layering(clazz)
+ verify_boolean(clazz)
+ verify_collections(clazz)
+ verify_flags(clazz)
+ verify_exception(clazz)
+ verify_google(clazz)
+ verify_bitset(clazz)
+ verify_manager(clazz)
+ verify_boxed(clazz)
+ verify_static_utils(clazz)
+ verify_overload_args(clazz)
+ verify_callback_handlers(clazz)
+ verify_context_first(clazz)
+ verify_listener_last(clazz)
+ verify_resource_names(clazz)
+
+
+def examine_stream(stream):
+ """Find all style issues in the given API stream."""
global failures
+ failures = {}
+ _parse_stream(stream, examine_clazz)
+ return failures
+
+def examine_api(api):
+ """Find all style issues in the given parsed API."""
+ global failures
failures = {}
for key in sorted(api.keys()):
- clazz = api[key]
-
- if clazz.pkg.name.startswith("java"): continue
- if clazz.pkg.name.startswith("junit"): continue
- if clazz.pkg.name.startswith("org.apache"): continue
- if clazz.pkg.name.startswith("org.xml"): continue
- if clazz.pkg.name.startswith("org.json"): continue
- if clazz.pkg.name.startswith("org.w3c"): continue
-
- verify_constants(clazz)
- verify_enums(clazz)
- verify_class_names(clazz)
- verify_method_names(clazz)
- verify_callbacks(clazz)
- verify_listeners(clazz)
- verify_actions(clazz)
- verify_extras(clazz)
- verify_equals(clazz)
- verify_parcelable(clazz)
- verify_protected(clazz)
- verify_fields(clazz)
- verify_register(clazz)
- verify_sync(clazz)
- verify_intent_builder(clazz)
- verify_helper_classes(clazz)
- verify_builder(clazz)
- verify_aidl(clazz)
- verify_internal(clazz)
- verify_layering(clazz)
- verify_boolean(clazz, api)
- verify_collections(clazz)
- verify_flags(clazz)
-
+ examine_clazz(api[key])
return failures
@@ -749,49 +1039,52 @@ def verify_compat(cur, prev):
prev_clazz = prev[key]
if not class_exists(cur, prev_clazz):
- error(prev_clazz, None, "Class removed or incompatible change")
+ error(prev_clazz, None, None, "Class removed or incompatible change")
continue
cur_clazz = cur[key]
for test in prev_clazz.ctors:
if not ctor_exists(cur, cur_clazz, test):
- error(prev_clazz, prev_ctor, "Constructor removed or incompatible change")
+ error(prev_clazz, prev_ctor, None, "Constructor removed or incompatible change")
methods = all_methods(prev, prev_clazz)
for test in methods:
if not method_exists(cur, cur_clazz, test):
- error(prev_clazz, test, "Method removed or incompatible change")
+ error(prev_clazz, test, None, "Method removed or incompatible change")
for test in prev_clazz.fields:
if not field_exists(cur, cur_clazz, test):
- error(prev_clazz, test, "Field removed or incompatible change")
+ error(prev_clazz, test, None, "Field removed or incompatible change")
return failures
-cur = parse_api(sys.argv[1])
-cur_fail = verify_style(cur)
+if __name__ == "__main__":
+ with open(sys.argv[1]) as f:
+ cur_fail = examine_stream(f)
-if len(sys.argv) > 2:
- prev = parse_api(sys.argv[2])
- prev_fail = verify_style(prev)
+ if len(sys.argv) > 2:
+ with open(sys.argv[2]) as f:
+ prev_fail = examine_stream(f)
- # ignore errors from previous API level
- for p in prev_fail:
- if p in cur_fail:
- del cur_fail[p]
+ # ignore errors from previous API level
+ for p in prev_fail:
+ if p in cur_fail:
+ del cur_fail[p]
- # look for compatibility issues
- compat_fail = verify_compat(cur, prev)
+ """
+ # NOTE: disabled because of memory pressure
+ # look for compatibility issues
+ compat_fail = verify_compat(cur, prev)
- print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
- for f in sorted(compat_fail):
- print compat_fail[f]
- print
+ print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+ for f in sorted(compat_fail):
+ print compat_fail[f]
+ print
+ """
-
-print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
-for f in sorted(cur_fail):
- print cur_fail[f]
- print
+ print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+ for f in sorted(cur_fail):
+ print cur_fail[f]
+ print
diff --git a/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml b/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml
index 595200245b43..a8736000a513 100644
--- a/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml
+++ b/tools/layoutlib/.idea/libraries/layoutlib_api_prebuilt.xml
@@ -5,7 +5,7 @@
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="file://$ANDROID_SRC$/tools/base/layoutlib-api/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/../../../../prebuilts/misc/common/layoutlib_api/layoutlib_api-sources.jar!/" />
</SOURCES>
</library>
</component> \ No newline at end of file
diff --git a/tools/layoutlib/.idea/misc.xml b/tools/layoutlib/.idea/misc.xml
index fa48f70ac6a1..94bcd36b4b37 100644
--- a/tools/layoutlib/.idea/misc.xml
+++ b/tools/layoutlib/.idea/misc.xml
@@ -9,7 +9,33 @@
<component name="FrameworkDetectionExcludesConfiguration">
<type id="android" />
</component>
- <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
+ <component name="NullableNotNullManager">
+ <option name="myDefaultNullable" value="com.android.annotations.Nullable" />
+ <option name="myDefaultNotNull" value="com.android.annotations.NonNull" />
+ <option name="myNullables">
+ <value>
+ <list size="5">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+ <item index="4" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
+ </list>
+ </value>
+ </option>
+ <option name="myNotNulls">
+ <value>
+ <list size="5">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+ <item index="4" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
+ </list>
+ </value>
+ </option>
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project> \ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 8d24d38711c2..970b9d042f60 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -76,13 +76,6 @@ public final class Bitmap_Delegate {
// ---- Public Helper methods ----
/**
- * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
- */
- public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
- return sManager.getDelegate(bitmap.mNativeBitmap);
- }
-
- /**
* Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
*/
public static Bitmap_Delegate getDelegate(long native_bitmap) {
@@ -187,19 +180,6 @@ public final class Bitmap_Delegate {
return createBitmap(delegate, createFlags, density.getDpiValue());
}
- /**
- * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
- */
- public static BufferedImage getImage(Bitmap bitmap) {
- // get the delegate from the native int.
- Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
- if (delegate == null) {
- return null;
- }
-
- return delegate.mImage;
- }
-
public static int getBufferedImageType(int nativeBitmapConfig) {
switch (Config.nativeToConfig(nativeBitmapConfig)) {
case ALPHA_8:
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java b/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
index b9928fce6c93..e4fcf1be32bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
@@ -37,17 +37,17 @@ import java.awt.image.WritableRaster;
*/
public final class BlendComposite implements Composite {
public enum BlendingMode {
- MULTIPLY(Multiply),
- SCREEN(Screen),
- DARKEN(Darken),
- LIGHTEN(Lighten),
- OVERLAY(Overlay),
- ADD(Add);
+ MULTIPLY(),
+ SCREEN(),
+ DARKEN(),
+ LIGHTEN(),
+ OVERLAY(),
+ ADD();
- private BlendComposite mComposite;
+ private final BlendComposite mComposite;
- BlendingMode(BlendComposite composite) {
- mComposite = composite;
+ BlendingMode() {
+ mComposite = new BlendComposite(this);
}
BlendComposite getBlendComposite() {
@@ -55,13 +55,6 @@ public final class BlendComposite implements Composite {
}
}
- public static final BlendComposite Multiply = new BlendComposite(BlendingMode.MULTIPLY);
- public static final BlendComposite Screen = new BlendComposite(BlendingMode.SCREEN);
- public static final BlendComposite Darken = new BlendComposite(BlendingMode.DARKEN);
- public static final BlendComposite Lighten = new BlendComposite(BlendingMode.LIGHTEN);
- public static final BlendComposite Overlay = new BlendComposite(BlendingMode.OVERLAY);
- public static final BlendComposite Add = new BlendComposite(BlendingMode.ADD);
-
private float alpha;
private BlendingMode mode;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index f42f48f04a47..1105c7b0fb19 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -661,9 +661,8 @@ public final class Matrix_Delegate {
float[] src = new float[] { radius, 0.f, 0.f, radius };
d.mapVectors(src, 0, src, 0, 2);
- float l1 = getPointLength(src, 0);
- float l2 = getPointLength(src, 2);
-
+ float l1 = (float) Math.hypot(src[0], src[1]);
+ float l2 = (float) Math.hypot(src[2], src[3]);
return (float) Math.sqrt(l1 * l2);
}
@@ -918,10 +917,6 @@ public final class Matrix_Delegate {
}
}
- private static float getPointLength(float[] src, int index) {
- return (float) Math.sqrt(src[index] * src[index] + src[index + 1] * src[index + 1]);
- }
-
/**
* multiply two matrices and store them in a 3rd.
* <p/>This in effect does dest = a*b
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 7b07404ca401..8ffd1d80a4e6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -251,7 +251,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getFlags(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -264,7 +264,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setFlags(Paint thisPaint, int flags) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -280,7 +280,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getHinting(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return Paint.HINTING_ON;
}
@@ -291,7 +291,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setHinting(Paint thisPaint, int mode) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -337,7 +337,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getColor(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -348,7 +348,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setColor(Paint thisPaint, int color) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -359,7 +359,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getAlpha(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -370,7 +370,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setAlpha(Paint thisPaint, int a) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -381,7 +381,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getStrokeWidth(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -392,7 +392,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -403,7 +403,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getStrokeMiter(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -414,7 +414,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -441,14 +441,14 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
}
@LayoutlibDelegate
/*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -459,7 +459,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getTextSize(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -470,7 +470,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setTextSize(Paint thisPaint, float textSize) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -482,7 +482,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getTextScaleX(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -493,7 +493,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -505,7 +505,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getTextSkewX(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -516,7 +516,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -528,7 +528,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float ascent(Paint thisPaint) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -545,7 +545,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float descent(Paint thisPaint) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -562,7 +562,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -573,7 +573,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -599,7 +599,7 @@ public class Paint_Delegate {
/*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
int count, int bidiFlags) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -1232,7 +1232,7 @@ public class Paint_Delegate {
private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 80179ee5703d..eb29835ded91 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -184,7 +184,7 @@ public class RadialGradient_Delegate extends Gradient_Delegate {
float _x = pt2[0];
float _y = pt2[1];
- float distance = (float) Math.sqrt(_x * _x + _y * _y);
+ float distance = (float) Math.hypot(_x, _y);
data[index++] = getGradientColor(distance / mRadius);
}
diff --git a/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
new file mode 100644
index 000000000000..24e4b54633e5
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
@@ -0,0 +1,193 @@
+/*
+ * 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.text;
+
+import com.android.annotations.NonNull;
+
+import android.text.Primitive.PrimitiveType;
+import android.text.StaticLayout.LineBreaks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.text.Primitive.PrimitiveType.PENALTY_INFINITY;
+
+// Based on the native implementation of GreedyLineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class GreedyLineBreaker extends LineBreaker {
+
+ public GreedyLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+ @NonNull TabStops tabStops) {
+ super(primitives, lineWidth, tabStops);
+ }
+
+ @Override
+ public void computeBreaks(LineBreaks lineBreaks) {
+ BreakInfo breakInfo = new BreakInfo();
+ int lineNum = 0;
+ float width = 0, printedWidth = 0;
+ boolean breakFound = false, goodBreakFound = false;
+ int breakIndex = 0, goodBreakIndex = 0;
+ float breakWidth = 0, goodBreakWidth = 0;
+ int firstTabIndex = Integer.MAX_VALUE;
+
+ float maxWidth = mLineWidth.getLineWidth(lineNum);
+
+ int numPrimitives = mPrimitives.size();
+ // greedily fit as many characters as possible on each line
+ // loop over all primitives, and choose the best break point
+ // (if possible, a break point without splitting a word)
+ // after going over the maximum length
+ for (int i = 0; i < numPrimitives; i++) {
+ Primitive p = mPrimitives.get(i);
+
+ // update the current line width
+ if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+ width += p.width;
+ if (p.type == PrimitiveType.BOX) {
+ printedWidth = width;
+ }
+ } else if (p.type == PrimitiveType.VARIABLE) {
+ width = mTabStops.width(width);
+ // keep track of first tab character in the region we are examining
+ // so we can determine whether or not a line contains a tab
+ firstTabIndex = Math.min(firstTabIndex, i);
+ }
+
+ // find the best break point for the characters examined so far
+ if (printedWidth > maxWidth) {
+ //noinspection StatementWithEmptyBody
+ if (breakFound || goodBreakFound) {
+ if (goodBreakFound) {
+ // a true line break opportunity existed in the characters examined so far,
+ // so there is no need to split a word
+ i = goodBreakIndex; // no +1 because of i++
+ lineNum++;
+ maxWidth = mLineWidth.getLineWidth(lineNum);
+ breakInfo.mBreaksList.add(mPrimitives.get(goodBreakIndex).location);
+ breakInfo.mWidthsList.add(goodBreakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < goodBreakIndex);
+ firstTabIndex = Integer.MAX_VALUE;
+ } else {
+ // must split a word because there is no other option
+ i = breakIndex; // no +1 because of i++
+ lineNum++;
+ maxWidth = mLineWidth.getLineWidth(lineNum);
+ breakInfo.mBreaksList.add(mPrimitives.get(breakIndex).location);
+ breakInfo.mWidthsList.add(breakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < breakIndex);
+ firstTabIndex = Integer.MAX_VALUE;
+ }
+ printedWidth = width = 0;
+ goodBreakFound = breakFound = false;
+ goodBreakWidth = breakWidth = 0;
+ continue;
+ } else {
+ // no choice, keep going... must make progress by putting at least one
+ // character on a line, even if part of that character is cut off --
+ // there is no other option
+ }
+ }
+
+ // update possible break points
+ if (p.type == PrimitiveType.PENALTY &&
+ p.penalty < PENALTY_INFINITY) {
+ // this does not handle penalties with width
+
+ // handle forced line break
+ if (p.penalty == -PENALTY_INFINITY) {
+ lineNum++;
+ maxWidth = mLineWidth.getLineWidth(lineNum);
+ breakInfo.mBreaksList.add(p.location);
+ breakInfo.mWidthsList.add(printedWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < i);
+ firstTabIndex = Integer.MAX_VALUE;
+ printedWidth = width = 0;
+ goodBreakFound = breakFound = false;
+ goodBreakWidth = breakWidth = 0;
+ continue;
+ }
+ if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
+ breakFound = true;
+ breakIndex = i;
+ breakWidth = printedWidth;
+ }
+ if (i > goodBreakIndex && printedWidth <= maxWidth) {
+ goodBreakFound = true;
+ goodBreakIndex = i;
+ goodBreakWidth = printedWidth;
+ }
+ } else if (p.type == PrimitiveType.WORD_BREAK) {
+ // only do this if necessary -- we don't want to break words
+ // when possible, but sometimes it is unavoidable
+ if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
+ breakFound = true;
+ breakIndex = i;
+ breakWidth = printedWidth;
+ }
+ }
+ }
+
+ if (breakFound || goodBreakFound) {
+ // output last break if there are more characters to output
+ if (goodBreakFound) {
+ breakInfo.mBreaksList.add(mPrimitives.get(goodBreakIndex).location);
+ breakInfo.mWidthsList.add(goodBreakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < goodBreakIndex);
+ } else {
+ breakInfo.mBreaksList.add(mPrimitives.get(breakIndex).location);
+ breakInfo.mWidthsList.add(breakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < breakIndex);
+ }
+ }
+ breakInfo.copyTo(lineBreaks);
+ }
+
+ private static class BreakInfo {
+ List<Integer> mBreaksList = new ArrayList<Integer>();
+ List<Float> mWidthsList = new ArrayList<Float>();
+ List<Boolean> mFlagsList = new ArrayList<Boolean>();
+
+ public void copyTo(LineBreaks lineBreaks) {
+ if (lineBreaks.breaks.length != mBreaksList.size()) {
+ lineBreaks.breaks = new int[mBreaksList.size()];
+ lineBreaks.widths = new float[mWidthsList.size()];
+ lineBreaks.flags = new boolean[mFlagsList.size()];
+ }
+
+ int i = 0;
+ for (int b : mBreaksList) {
+ lineBreaks.breaks[i] = b;
+ i++;
+ }
+ i = 0;
+ for (float b : mWidthsList) {
+ lineBreaks.widths[i] = b;
+ i++;
+ }
+ i = 0;
+ for (boolean b : mFlagsList) {
+ lineBreaks.flags[i] = b;
+ i++;
+ }
+
+ mBreaksList = null;
+ mWidthsList = null;
+ mFlagsList = null;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/LineBreaker.java b/tools/layoutlib/bridge/src/android/text/LineBreaker.java
new file mode 100644
index 000000000000..8be36352dbab
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/LineBreaker.java
@@ -0,0 +1,42 @@
+/*
+ * 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.text;
+
+import android.text.StaticLayout.LineBreaks;
+import com.android.annotations.NonNull;
+
+import java.util.Collections;
+import java.util.List;
+
+// Based on the native implementation of LineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public abstract class LineBreaker {
+
+ protected final @NonNull List<Primitive> mPrimitives;
+ protected final @NonNull LineWidth mLineWidth;
+ protected final @NonNull TabStops mTabStops;
+
+ public LineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+ @NonNull TabStops tabStops) {
+ mPrimitives = Collections.unmodifiableList(primitives);
+ mLineWidth = lineWidth;
+ mTabStops = tabStops;
+ }
+
+ @NonNull
+ public abstract void computeBreaks(@NonNull LineBreaks breakInfo);
+}
diff --git a/tools/layoutlib/bridge/src/android/text/LineWidth.java b/tools/layoutlib/bridge/src/android/text/LineWidth.java
new file mode 100644
index 000000000000..2ea886df88a4
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/LineWidth.java
@@ -0,0 +1,35 @@
+/*
+ * 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.text;
+
+// Based on the native implementation of LineWidth in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class LineWidth {
+ private final float mFirstWidth;
+ private final int mFirstWidthLineCount;
+ private float mRestWidth;
+
+ public LineWidth(float firstWidth, int firstWidthLineCount, float restWidth) {
+ mFirstWidth = firstWidth;
+ mFirstWidthLineCount = firstWidthLineCount;
+ mRestWidth = restWidth;
+ }
+
+ public float getLineWidth(int line) {
+ return (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
new file mode 100644
index 000000000000..d5d77983b56b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
@@ -0,0 +1,262 @@
+/*
+ * 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.text;
+
+import com.android.annotations.NonNull;
+
+import android.text.Primitive.PrimitiveType;
+import android.text.StaticLayout.LineBreaks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import static android.text.Primitive.PrimitiveType.PENALTY_INFINITY;
+
+
+// Based on the native implementation of OptimizingLineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+/**
+ * A more complex version of line breaking where we try to prevent the right edge from being too
+ * jagged.
+ */
+public class OptimizingLineBreaker extends LineBreaker {
+
+ public OptimizingLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+ @NonNull TabStops tabStops) {
+ super(primitives, lineWidth, tabStops);
+ }
+
+ @Override
+ public void computeBreaks(@NonNull LineBreaks breakInfo) {
+ int numBreaks = mPrimitives.size();
+ assert numBreaks > 0;
+ if (numBreaks == 1) {
+ // This can be true only if it's an empty paragraph.
+ Primitive p = mPrimitives.get(0);
+ assert p.type == PrimitiveType.PENALTY;
+ breakInfo.breaks = new int[]{0};
+ breakInfo.widths = new float[]{p.width};
+ breakInfo.flags = new boolean[]{false};
+ return;
+ }
+ Node[] opt = new Node[numBreaks];
+ opt[0] = new Node(-1, 0, 0, 0, false);
+ opt[numBreaks - 1] = new Node(-1, 0, 0, 0, false);
+
+ ArrayList<Integer> active = new ArrayList<Integer>();
+ active.add(0);
+ int lastBreak = 0;
+ for (int i = 0; i < numBreaks; i++) {
+ Primitive p = mPrimitives.get(i);
+ if (p.type == PrimitiveType.PENALTY) {
+ boolean finalBreak = (i + 1 == numBreaks);
+ Node bestBreak = null;
+
+ for (ListIterator<Integer> it = active.listIterator(); it.hasNext();
+ /* incrementing done in loop */) {
+ int pos = it.next();
+ int lines = opt[pos].mPrevCount;
+ float maxWidth = mLineWidth.getLineWidth(lines);
+ // we have to compute metrics every time --
+ // we can't really pre-compute this stuff and just deal with breaks
+ // because of the way tab characters work, this makes it computationally
+ // harder, but this way, we can still optimize while treating tab characters
+ // correctly
+ LineMetrics lineMetrics = computeMetrics(pos, i);
+ if (lineMetrics.mPrintedWidth <= maxWidth) {
+ float demerits = computeDemerits(maxWidth, lineMetrics.mPrintedWidth,
+ finalBreak, p.penalty) + opt[pos].mDemerits;
+ if (bestBreak == null || demerits < bestBreak.mDemerits) {
+ if (bestBreak == null) {
+ bestBreak = new Node(pos, opt[pos].mPrevCount + 1, demerits,
+ lineMetrics.mPrintedWidth, lineMetrics.mHasTabs);
+ } else {
+ bestBreak.mPrev = pos;
+ bestBreak.mPrevCount = opt[pos].mPrevCount + 1;
+ bestBreak.mDemerits = demerits;
+ bestBreak.mWidth = lineMetrics.mPrintedWidth;
+ bestBreak.mHasTabs = lineMetrics.mHasTabs;
+ }
+ }
+ } else {
+ it.remove();
+ }
+ }
+ if (p.penalty == -PENALTY_INFINITY) {
+ active.clear();
+ }
+ if (bestBreak != null) {
+ opt[i] = bestBreak;
+ active.add(i);
+ lastBreak = i;
+ }
+ if (active.isEmpty()) {
+ // we can't give up!
+ LineMetrics lineMetrics = new LineMetrics();
+ int lines = opt[lastBreak].mPrevCount;
+ float maxWidth = mLineWidth.getLineWidth(lines);
+ int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, lineMetrics);
+ opt[breakIndex] = new Node(lastBreak, lines + 1, 0 /*doesn't matter*/,
+ lineMetrics.mWidth, lineMetrics.mHasTabs);
+ active.add(breakIndex);
+ lastBreak = breakIndex;
+ i = breakIndex; // incremented by i++
+ }
+ }
+ }
+
+ int idx = numBreaks - 1;
+ int count = opt[idx].mPrevCount;
+ resize(breakInfo, count);
+ while (opt[idx].mPrev != -1) {
+ count--;
+ assert count >=0;
+
+ breakInfo.breaks[count] = mPrimitives.get(idx).location;
+ breakInfo.widths[count] = opt[idx].mWidth;
+ breakInfo.flags [count] = opt[idx].mHasTabs;
+ idx = opt[idx].mPrev;
+ }
+ }
+
+ private static void resize(LineBreaks lineBreaks, int size) {
+ if (lineBreaks.breaks.length == size) {
+ return;
+ }
+ int[] breaks = new int[size];
+ float[] widths = new float[size];
+ boolean[] flags = new boolean[size];
+
+ int toCopy = Math.min(size, lineBreaks.breaks.length);
+ System.arraycopy(lineBreaks.breaks, 0, breaks, 0, toCopy);
+ System.arraycopy(lineBreaks.widths, 0, widths, 0, toCopy);
+ System.arraycopy(lineBreaks.flags, 0, flags, 0, toCopy);
+
+ lineBreaks.breaks = breaks;
+ lineBreaks.widths = widths;
+ lineBreaks.flags = flags;
+ }
+
+ @NonNull
+ private LineMetrics computeMetrics(int start, int end) {
+ boolean f = false;
+ float w = 0, pw = 0;
+ for (int i = start; i < end; i++) {
+ Primitive p = mPrimitives.get(i);
+ if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+ w += p.width;
+ if (p.type == PrimitiveType.BOX) {
+ pw = w;
+ }
+ } else if (p.type == PrimitiveType.VARIABLE) {
+ w = mTabStops.width(w);
+ f = true;
+ }
+ }
+ return new LineMetrics(w, pw, f);
+ }
+
+ private static float computeDemerits(float maxWidth, float width, boolean finalBreak,
+ float penalty) {
+ float deviation = finalBreak ? 0 : maxWidth - width;
+ return (deviation * deviation) + penalty;
+ }
+
+ /**
+ * @return the last break position or -1 if failed.
+ */
+ @SuppressWarnings("ConstantConditions") // method too complex to be analyzed.
+ private int desperateBreak(int start, int limit, float maxWidth,
+ @NonNull LineMetrics lineMetrics) {
+ float w = 0, pw = 0;
+ boolean breakFound = false;
+ int breakIndex = 0, firstTabIndex = Integer.MAX_VALUE;
+ for (int i = start; i < limit; i++) {
+ Primitive p = mPrimitives.get(i);
+
+ if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+ w += p.width;
+ if (p.type == PrimitiveType.BOX) {
+ pw = w;
+ }
+ } else if (p.type == PrimitiveType.VARIABLE) {
+ w = mTabStops.width(w);
+ firstTabIndex = Math.min(firstTabIndex, i);
+ }
+
+ if (pw > maxWidth && breakFound) {
+ break;
+ }
+
+ // must make progress
+ if (i > start &&
+ (p.type == PrimitiveType.PENALTY || p.type == PrimitiveType.WORD_BREAK)) {
+ breakFound = true;
+ breakIndex = i;
+ }
+ }
+
+ if (breakFound) {
+ lineMetrics.mWidth = w;
+ lineMetrics.mPrintedWidth = pw;
+ lineMetrics.mHasTabs = (start <= firstTabIndex && firstTabIndex < breakIndex);
+ return breakIndex;
+ } else {
+ return -1;
+ }
+ }
+
+ private static class LineMetrics {
+ /** Actual width of the line. */
+ float mWidth;
+ /** Width of the line minus trailing whitespace. */
+ float mPrintedWidth;
+ boolean mHasTabs;
+
+ public LineMetrics() {
+ }
+
+ public LineMetrics(float width, float printedWidth, boolean hasTabs) {
+ mWidth = width;
+ mPrintedWidth = printedWidth;
+ mHasTabs = hasTabs;
+ }
+ }
+
+ /**
+ * A struct to store the info about a break.
+ */
+ @SuppressWarnings("SpellCheckingInspection") // For the word struct.
+ private static class Node {
+ // -1 for the first node.
+ int mPrev;
+ // number of breaks so far.
+ int mPrevCount;
+ float mDemerits;
+ float mWidth;
+ boolean mHasTabs;
+
+ public Node(int prev, int prevCount, float demerits, float width, boolean hasTabs) {
+ mPrev = prev;
+ mPrevCount = prevCount;
+ mDemerits = demerits;
+ mWidth = width;
+ mHasTabs = hasTabs;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/Primitive.java b/tools/layoutlib/bridge/src/android/text/Primitive.java
new file mode 100644
index 000000000000..ce77601582c9
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/Primitive.java
@@ -0,0 +1,92 @@
+/*
+ * 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.text;
+
+import com.android.annotations.NonNull;
+
+// Based on the native implementation of Primitive in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class Primitive {
+ public final @NonNull PrimitiveType type;
+ public final int location;
+ // The following fields don't make sense for all types.
+ // Box and Glue have width only.
+ // Penalty has both width and penalty.
+ // Word_break has penalty only.
+ public final float width;
+ public final float penalty;
+
+ /**
+ * Use {@code PrimitiveType#getNewPrimitive()}
+ */
+ private Primitive(@NonNull PrimitiveType type, int location, float width, float penalty) {
+ this.type = type;
+ this.location = location;
+ this.width = width;
+ this.penalty = penalty;
+ }
+
+ public static enum PrimitiveType {
+ /**
+ * Something with a constant width that is to be typeset - like a character.
+ */
+ BOX,
+ /**
+ * Blank space with fixed width.
+ */
+ GLUE,
+ /**
+ * Aesthetic cost indicating how desirable breaking at this point will be. A penalty of
+ * {@link #PENALTY_INFINITY} means a forced non-break, whereas a penalty of negative
+ * {@code #PENALTY_INFINITY} means a forced break.
+ * <p/>
+ * Currently, it only stores penalty with values 0 or -infinity.
+ */
+ PENALTY,
+ /**
+ * For tabs - variable width space.
+ */
+ VARIABLE,
+ /**
+ * Possible breakpoints within a word. Think of this as a high cost {@link #PENALTY}.
+ */
+ WORD_BREAK;
+
+ public Primitive getNewPrimitive(int location) {
+ assert this == VARIABLE;
+ return new Primitive(this, location, 0f, 0f);
+ }
+
+ public Primitive getNewPrimitive(int location, float value) {
+ assert this == BOX || this == GLUE || this == WORD_BREAK;
+ if (this == BOX || this == GLUE) {
+ return new Primitive(this, location, value, 0f);
+ } else {
+ return new Primitive(this, location, 0f, value);
+ }
+ }
+
+ public Primitive getNewPrimitive(int location, float width, float penalty) {
+ assert this == PENALTY;
+ return new Primitive(this, location, width, penalty);
+ }
+
+ // forced non-break, negative infinity is forced break.
+ public static final float PENALTY_INFINITY = 1e7f;
+ }
+}
+
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index b0d79a8e8f22..e24b3d5ec7ef 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -1,12 +1,15 @@
package android.text;
+import com.android.annotations.NonNull;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-import java.text.CharacterIterator;
-import java.util.Arrays;
-import java.util.Locale;
+import android.text.StaticLayout.LineBreaks;
+import android.text.Primitive.PrimitiveType;
+
+import java.util.ArrayList;
+import java.util.List;
-import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.BreakIterator;
import com.ibm.icu.util.ULocale;
import javax.swing.text.Segment;
@@ -20,36 +23,112 @@ import javax.swing.text.Segment;
*/
public class StaticLayout_Delegate {
- /**
- * Fills the recycle array with positions that are suitable to break the text at. The array
- * must be terminated by '-1'.
- */
+ private static final char CHAR_SPACE = 0x20;
+ private static final char CHAR_TAB = 0x09;
+ private static final char CHAR_NEWLINE = 0x0A;
+ private static final char CHAR_ZWSP = 0x200B; // Zero width space.
+
+ // ---- Builder delegate manager ----
+ private static final DelegateManager<Builder> sBuilderManager =
+ new DelegateManager<Builder>(Builder.class);
+
@LayoutlibDelegate
- /*package*/ static int[] nLineBreakOpportunities(String locale, char[] text, int length,
- int[] recycle) {
- BreakIterator iterator = BreakIterator.getLineInstance(new ULocale(locale));
- Segment segment = new Segment(text, 0, length);
- iterator.setText(segment);
- if (recycle == null) {
- // Because 42 is the answer to everything.
- recycle = new int[42];
+ /*package*/ static int nComputeLineBreaks(long nativeBuilder, char[] inputText, float[] widths,
+ int length, float firstWidth, int firstWidthLineCount, float restWidth,
+ int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
+ int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) {
+
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ // compute all possible breakpoints.
+ BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
+ it.setText(new Segment(inputText, 0, length));
+ // average word length in english is 5. So, initialize the possible breaks with a guess.
+ List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
+ int loc;
+ it.first();
+ while ((loc = it.next()) != BreakIterator.DONE) {
+ breaks.add(loc);
+ }
+
+ LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
+ TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
+ List<Primitive> primitives = computePrimitives(inputText, widths, length, breaks);
+ LineBreaker lineBreaker;
+ if (optimize) {
+ lineBreaker = new OptimizingLineBreaker(primitives, lineWidth, tabStopCalculator);
+ } else {
+ lineBreaker = new GreedyLineBreaker(primitives, lineWidth, tabStopCalculator);
}
- int breakOpp = iterator.first();
- recycle[0] = breakOpp;
- //noinspection ConstantConditions
- assert BreakIterator.DONE == -1;
- for (int i = 1; breakOpp != BreakIterator.DONE; ++i) {
- if (i >= recycle.length) {
- recycle = doubleSize(recycle);
+ lineBreaker.computeBreaks(recycle);
+ return recycle.breaks.length;
+ }
+
+ /**
+ * Compute metadata each character - things which help in deciding if it's possible to break
+ * at a point or not.
+ */
+ @NonNull
+ private static List<Primitive> computePrimitives(@NonNull char[] text, @NonNull float[] widths,
+ int length, @NonNull List<Integer> breaks) {
+ // Initialize the list with a guess of the number of primitives:
+ // 2 Primitives per non-whitespace char and approx 5 chars per word (i.e. 83% chars)
+ List<Primitive> primitives = new ArrayList<Primitive>(((int) Math.ceil(length * 1.833)));
+ int breaksSize = breaks.size();
+ int breakIndex = 0;
+ for (int i = 0; i < length; i++) {
+ char c = text[i];
+ if (c == CHAR_SPACE || c == CHAR_ZWSP) {
+ primitives.add(PrimitiveType.GLUE.getNewPrimitive(i, widths[i]));
+ } else if (c == CHAR_TAB) {
+ primitives.add(PrimitiveType.VARIABLE.getNewPrimitive(i));
+ } else if (c != CHAR_NEWLINE) {
+ while (breakIndex < breaksSize && breaks.get(breakIndex) < i) {
+ breakIndex++;
+ }
+ Primitive p;
+ if (widths[i] != 0) {
+ if (breakIndex < breaksSize && breaks.get(breakIndex) == i) {
+ p = PrimitiveType.PENALTY.getNewPrimitive(i, 0, 0);
+ } else {
+ p = PrimitiveType.WORD_BREAK.getNewPrimitive(i, 0);
+ }
+ primitives.add(p);
+ }
+
+ primitives.add(PrimitiveType.BOX.getNewPrimitive(i, widths[i]));
}
- assert (i < recycle.length);
- breakOpp = iterator.next();
- recycle[i] = breakOpp;
}
- return recycle;
+ // final break at end of everything
+ primitives.add(
+ PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY));
+ return primitives;
}
- private static int[] doubleSize(int[] array) {
- return Arrays.copyOf(array, array.length * 2);
+ @LayoutlibDelegate
+ /*package*/ static long nNewBuilder() {
+ return sBuilderManager.addNewDelegate(new Builder());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nFinishBuilder(long nativeBuilder) {
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nFreeBuilder(long nativeBuilder) {
+ sBuilderManager.removeJavaReferenceFor(nativeBuilder);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nBuilderSetLocale(long nativeBuilder, String locale) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ builder.mLocale = locale;
+ }
+
+ /**
+ * Java representation of the native Builder class. It currently only stores the locale
+ * set by nBuilderSetLocale.
+ */
+ static class Builder {
+ String mLocale;
}
}
diff --git a/tools/layoutlib/bridge/src/android/text/TabStops.java b/tools/layoutlib/bridge/src/android/text/TabStops.java
new file mode 100644
index 000000000000..cff6b93e8361
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/TabStops.java
@@ -0,0 +1,44 @@
+/*
+ * 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.text;
+
+import com.android.annotations.Nullable;
+
+// Based on the native implementation of TabStops in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class TabStops {
+ @Nullable
+ private int[] mStops;
+ private final int mTabWidth;
+
+ public TabStops(@Nullable int[] stops, int defaultTabWidth) {
+ mTabWidth = defaultTabWidth;
+ mStops = stops;
+ }
+
+ public float width(float widthSoFar) {
+ if (mStops != null) {
+ for (int i : mStops) {
+ if (i > widthSoFar) {
+ return i;
+ }
+ }
+ }
+ // find the next tabStop after widthSoFar.
+ return (int) ((widthSoFar + mTabWidth) / mTabWidth) * mTabWidth;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
deleted file mode 100644
index 8b4c60b5fead..000000000000
--- a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2007 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.util;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.util.FloatMath
- *
- * Through the layoutlib_create tool, the original native methods of FloatMath 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.
- *
- */
-/*package*/ final class FloatMath_Delegate {
-
- /** Prevents instantiation. */
- private FloatMath_Delegate() {}
-
- /**
- * Returns the float conversion of the most positive (i.e. closest to
- * positive infinity) integer value which is less than the argument.
- *
- * @param value to be converted
- * @return the floor of value
- */
- @LayoutlibDelegate
- /*package*/ static float floor(float value) {
- return (float)Math.floor(value);
- }
-
- /**
- * Returns the float conversion of the most negative (i.e. closest to
- * negative infinity) integer value which is greater than the argument.
- *
- * @param value to be converted
- * @return the ceiling of value
- */
- @LayoutlibDelegate
- /*package*/ static float ceil(float value) {
- return (float)Math.ceil(value);
- }
-
- /**
- * Returns the closest float approximation of the sine of the argument.
- *
- * @param angle to compute the cosine of, in radians
- * @return the sine of angle
- */
- @LayoutlibDelegate
- /*package*/ static float sin(float angle) {
- return (float)Math.sin(angle);
- }
-
- /**
- * Returns the closest float approximation of the cosine of the argument.
- *
- * @param angle to compute the cosine of, in radians
- * @return the cosine of angle
- */
- @LayoutlibDelegate
- /*package*/ static float cos(float angle) {
- return (float)Math.cos(angle);
- }
-
- /**
- * Returns the closest float approximation of the square root of the
- * argument.
- *
- * @param value to compute sqrt of
- * @return the square root of value
- */
- @LayoutlibDelegate
- /*package*/ static float sqrt(float value) {
- return (float)Math.sqrt(value);
- }
-
- /**
- * Returns the closest float approximation of the raising "e" to the power
- * of the argument.
- *
- * @param value to compute the exponential of
- * @return the exponential of value
- */
- @LayoutlibDelegate
- /*package*/ static float exp(float value) {
- return (float)Math.exp(value);
- }
-
- /**
- * Returns the closest float approximation of the result of raising {@code
- * x} to the power of {@code y}.
- *
- * @param x the base of the operation.
- * @param y the exponent of the operation.
- * @return {@code x} to the power of {@code y}.
- */
- @LayoutlibDelegate
- /*package*/ static float pow(float x, float y) {
- return (float)Math.pow(x, y);
- }
-
- /**
- * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
- * {@code y}</i><sup>{@code 2}</sup>{@code )}.
- *
- * @param x a float number
- * @param y a float number
- * @return the hypotenuse
- */
- @LayoutlibDelegate
- /*package*/ static float hypot(float x, float y) {
- return (float)Math.sqrt(x*x + y*y);
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 7e4ff6983315..8192b5fbbf82 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -22,9 +22,13 @@ import com.android.ide.common.rendering.api.MergeCookie;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
+import com.android.layoutlib.bridge.android.support.RecyclerViewUtil.LayoutManagerType;
import com.android.layoutlib.bridge.impl.ParserFactory;
+import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.resources.ResourceType;
import com.android.util.Pair;
@@ -111,8 +115,7 @@ public final class BridgeInflater extends LayoutInflater {
} catch (Exception e) {
// Wrap the real exception in a ClassNotFoundException, so that the calling method
// can deal with it.
- ClassNotFoundException exception = new ClassNotFoundException("onCreateView", e);
- throw exception;
+ throw new ClassNotFoundException("onCreateView", e);
}
setupViewInContext(view, attrs);
@@ -123,7 +126,7 @@ public final class BridgeInflater extends LayoutInflater {
@Override
public View createViewFromTag(View parent, String name, AttributeSet attrs,
boolean inheritContext) {
- View view = null;
+ View view;
try {
view = super.createViewFromTag(parent, name, attrs, inheritContext);
} catch (InflateException e) {
@@ -134,7 +137,7 @@ public final class BridgeInflater extends LayoutInflater {
// Wrap the real exception in an InflateException so that the calling
// method can deal with it.
InflateException exception = new InflateException();
- if (e2.getClass().equals(ClassNotFoundException.class) == false) {
+ if (!e2.getClass().equals(ClassNotFoundException.class)) {
exception.initCause(e2);
} else {
exception.initCause(e);
@@ -184,7 +187,7 @@ public final class BridgeInflater extends LayoutInflater {
return inflate(bridgeParser, root);
} catch (Exception e) {
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- "Failed to parse file " + f.getAbsolutePath(), e, null /*data*/);
+ "Failed to parse file " + f.getAbsolutePath(), e, null);
return null;
}
@@ -194,8 +197,7 @@ public final class BridgeInflater extends LayoutInflater {
return null;
}
- private View loadCustomView(String name, AttributeSet attrs) throws ClassNotFoundException,
- Exception{
+ private View loadCustomView(String name, AttributeSet attrs) throws Exception {
if (mProjectCallback != null) {
// first get the classname in case it's not the node name
if (name.equals("view")) {
@@ -227,6 +229,22 @@ public final class BridgeInflater extends LayoutInflater {
if (viewKey != null) {
bc.addViewKey(view, viewKey);
}
+ if (RenderSessionImpl.isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
+ String type = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES,
+ BridgeConstants.ATTR_LAYOUT_MANAGER_TYPE);
+ if (type != null) {
+ LayoutManagerType layoutManagerType = LayoutManagerType.getByLogicalName(type);
+ if (layoutManagerType == null) {
+ layoutManagerType = LayoutManagerType.getByClassName(type);
+ }
+ if (layoutManagerType == null) {
+ // add the classname itself.
+ bc.addCookie(view, type);
+ } else {
+ bc.addCookie(view, layoutManagerType);
+ }
+ }
+ }
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 5176419a8b68..32305a090d76 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -215,6 +215,12 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void overridePendingAppTransitionClipReveal(int startX, int startY,
+ int startWidth, int startHeight) throws RemoteException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
IRemoteCallback startedCallback, boolean scaleUp) throws RemoteException {
// TODO Auto-generated method stub
@@ -293,7 +299,7 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
+ public void setAppTask(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
index 38846bdbb303..a0db7bfadb05 100644
--- a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
@@ -65,6 +65,9 @@ public class ShadowPainter {
@SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"}) // Imported code
public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
float shadowOpacity, int shadowRgb) {
+ if (shadowSize == 0) {
+ return source;
+ }
// This code is based on
// http://www.jroller.com/gfx/entry/non_rectangular_shadow
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index 78242a8ab08e..823b2478458f 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -120,6 +120,11 @@ public class WindowCallback implements Window.Callback {
}
@Override
+ public ActionMode onWindowStartingActionMode(Callback callback, int type) {
+ return null;
+ }
+
+ @Override
public void onActionModeStarted(ActionMode mode) {
}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java b/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 0100dc591039..000000000000
--- a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 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 com.android.internal.policy;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.RenderAction;
-
-import android.content.Context;
-import android.view.BridgeInflater;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * Custom implementation of PolicyManager that does nothing to run in LayoutLib.
- *
- */
-public class PolicyManager {
-
- public static Window makeNewWindow(Context context) {
- // this will likely crash somewhere beyond so we log it.
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
- "Call to PolicyManager.makeNewWindow is not supported", null);
- return null;
- }
-
- public static LayoutInflater makeNewLayoutInflater(Context context) {
- return new BridgeInflater(context, RenderAction.getCurrentContext().getProjectCallback());
- }
-
- public static WindowManagerPolicy makeNewWindowManager() {
- // this will likely crash somewhere beyond so we log it.
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
- "Call to PolicyManager.makeNewWindowManager is not supported", null);
- return null;
- }
-
- public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
- return new FallbackEventHandler() {
- @Override
- public void setView(View v) {
- }
-
- @Override
- public void preDispatchKeyEvent(KeyEvent event) {
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- return false;
- }
- };
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 4d2c2fc20588..c6d60f8a76f6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -181,7 +181,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
*/
private static LayoutLog sCurrentLog = sDefaultLog;
- private static final int LAST_SUPPORTED_FEATURE = Features.PREFERENCES_RENDERING;
+ private static final int LAST_SUPPORTED_FEATURE = Features.RENDER_ALL_DRAWABLE_STATES;
@Override
public int getApiLevel() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index eb9e7f1dafb3..1af69982236e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -48,4 +48,7 @@ public class BridgeConstants {
public final static String MATCH_PARENT = "match_parent";
public final static String FILL_PARENT = "fill_parent";
public final static String WRAP_CONTENT = "wrap_content";
+
+ /** Attribute in the tools namespace used to specify layout manager for RecyclerView. */
+ public static final String ATTR_LAYOUT_MANAGER_TYPE = "layoutManager";
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index e0f87fd63b11..feb25905390c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -86,11 +86,14 @@ public class BridgeRenderSession extends RenderSession {
}
@Override
- public Result render(long timeout) {
+ public Result render(long timeout, boolean forceMeasure) {
try {
Bridge.prepareThread();
mLastResult = mSession.acquire(timeout);
if (mLastResult.isSuccess()) {
+ if (forceMeasure) {
+ mSession.invalidateRenderingSize();
+ }
mLastResult = mSession.render(false /*freshRender*/);
}
} finally {
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 2f62b93ede6a..179a8e773482 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
@@ -16,7 +16,6 @@
package com.android.layoutlib.bridge.android;
-import android.os.IBinder;
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.AssetRepository;
import com.android.ide.common.rendering.api.ILayoutPullParser;
@@ -64,6 +63,7 @@ import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
@@ -73,6 +73,7 @@ import android.util.TypedValue;
import android.view.BridgeInflater;
import android.view.Display;
import android.view.DisplayAdjustments;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -94,6 +95,7 @@ import java.util.Map;
/**
* Custom implementation of Context/Activity to handle non compiled resources.
*/
+@SuppressWarnings("deprecation") // For use of Pair.
public final class BridgeContext extends Context {
/** The map adds cookies to each view so that IDE can link xml tags to views. */
@@ -495,6 +497,34 @@ public final class BridgeContext extends Context {
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
+ @Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ if (serviceClass.equals(LayoutInflater.class)) {
+ return LAYOUT_INFLATER_SERVICE;
+ }
+
+ if (serviceClass.equals(TextServicesManager.class)) {
+ return TEXT_SERVICES_MANAGER_SERVICE;
+ }
+
+ if (serviceClass.equals(WindowManager.class)) {
+ return WINDOW_SERVICE;
+ }
+
+ if (serviceClass.equals(PowerManager.class)) {
+ return POWER_SERVICE;
+ }
+
+ if (serviceClass.equals(DisplayManager.class)) {
+ return DISPLAY_SERVICE;
+ }
+
+ if (serviceClass.equals(AccessibilityManager.class)) {
+ return ACCESSIBILITY_SERVICE;
+ }
+
+ throw new UnsupportedOperationException("Unsupported Service: " + serviceClass);
+ }
@Override
public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {
@@ -569,7 +599,7 @@ public final class BridgeContext extends Context {
// Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
if (set instanceof BridgeXmlBlockParser) {
- BridgeXmlBlockParser parser = null;
+ BridgeXmlBlockParser parser;
parser = (BridgeXmlBlockParser)set;
isPlatformFile = parser.isPlatformFile();
@@ -590,7 +620,7 @@ public final class BridgeContext extends Context {
} else if (set != null) { // null parser is ok
// really this should not be happening since its instantiated in Bridge
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Parser is not a BridgeXmlBlockParser!", null /*data*/);
+ "Parser is not a BridgeXmlBlockParser!", null);
return null;
}
@@ -602,7 +632,7 @@ public final class BridgeContext extends Context {
// look for a custom style.
String customStyle = null;
if (set != null) {
- customStyle = set.getAttributeValue(null /* namespace*/, "style");
+ customStyle = set.getAttributeValue(null, "style");
}
StyleResourceValue customStyleValues = null;
@@ -625,31 +655,39 @@ public final class BridgeContext extends Context {
// get the name from the int.
Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr);
- if (defaultPropMap != null) {
- String defStyleName = defStyleAttribute.getFirst();
- if (defStyleAttribute.getSecond()) {
- defStyleName = "android:" + defStyleName;
+ if (defStyleAttribute == null) {
+ // This should be rare. Happens trying to map R.style.foo to @style/foo fails.
+ // This will happen if the user explicitly used a non existing int value for
+ // defStyleAttr or there's something wrong with the project structure/build.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
+ "Failed to find the style corresponding to the id " + defStyleAttr, null);
+ } else {
+ if (defaultPropMap != null) {
+ String defStyleName = defStyleAttribute.getFirst();
+ if (defStyleAttribute.getSecond()) {
+ defStyleName = "android:" + defStyleName;
+ }
+ defaultPropMap.put("style", defStyleName);
}
- defaultPropMap.put("style", defStyleName);
- }
- // look for the style in the current theme, and its parent:
- ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(),
- defStyleAttribute.getSecond());
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(),
+ defStyleAttribute.getSecond());
- if (item != null) {
- // item is a reference to a style entry. Search for it.
- item = mRenderResources.findResValue(item.getValue(), item.isFramework());
+ if (item != null) {
+ // item is a reference to a style entry. Search for it.
+ item = mRenderResources.findResValue(item.getValue(), item.isFramework());
- if (item instanceof StyleResourceValue) {
- defStyleValues = (StyleResourceValue)item;
+ if (item instanceof StyleResourceValue) {
+ defStyleValues = (StyleResourceValue) item;
+ }
+ } else {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
+ String.format(
+ "Failed to find style '%s' in current theme",
+ defStyleAttribute.getFirst()),
+ null);
}
- } else {
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
- String.format(
- "Failed to find style '%s' in current theme",
- defStyleAttribute.getFirst()),
- null /*data*/);
}
} else if (defStyleRes != 0) {
boolean isFrameworkRes = true;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 0f51d00ca62d..4289689a37f5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -191,12 +191,6 @@ public final class BridgeWindowSession implements IWindowSession {
}
@Override
- public void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
- float dsdx, float dtdx, float dsdy, float dtdy) {
- // pass for now.
- }
-
- @Override
public IBinder asBinder() {
// pass for now.
return null;
@@ -212,4 +206,9 @@ public final class BridgeWindowSession implements IWindowSession {
// pass for now.
return null;
}
+
+ @Override
+ public void pokeDrawLock(IBinder window) {
+ // pass for now.
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
index e00ea6a207fa..2f45473bf53b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -16,20 +16,26 @@
package com.android.layoutlib.bridge.android;
-import com.android.ide.common.rendering.api.SessionParams;
+import com.android.ide.common.rendering.api.SessionParams.Key;
/**
- * This contains all known keys for the {@link SessionParams#getFlag(SessionParams.Key)}.
+ * This contains all known keys for the {@link RenderParams#getFlag(Key)}.
* <p/>
* The IDE has its own copy of this class which may be newer or older than this one.
* <p/>
* Constants should never be modified or removed from this class.
*/
-public final class SessionParamsFlags {
+public final class RenderParamsFlags {
- public static final SessionParams.Key<String> FLAG_KEY_ROOT_TAG =
- new SessionParams.Key<String>("rootTag", String.class);
+ public static final Key<String> FLAG_KEY_ROOT_TAG =
+ new Key<String>("rootTag", String.class);
+ public static final Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
+ new Key<Boolean>("disableBitmapCaching", Boolean.class);
+ public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT =
+ new Key<Boolean>("recyclerViewSupport", Boolean.class);
+ public static final Key<Boolean> FLAG_KEY_RENDER_ALL_DRAWABLE_STATES =
+ new Key<Boolean>("renderAllDrawableStates", Boolean.class);
// Disallow instances.
- private SessionParamsFlags() {}
+ private RenderParamsFlags() {}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
new file mode 100644
index 000000000000..b72329af2a9d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2015 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 com.android.layoutlib.bridge.android.support;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+import static com.android.layoutlib.bridge.util.ReflectionUtils.*;
+
+/**
+ * Utility class for working with android.support.v7.widget.RecyclerView
+ */
+@SuppressWarnings("SpellCheckingInspection") // for "recycler".
+public class RecyclerViewUtil {
+
+ /**
+ * Used by {@link LayoutManagerType}.
+ * <p/>
+ * Not declared inside the enum, since it needs to be accessible in the constructor.
+ */
+ private static final Object CONTEXT = new Object();
+
+ public static final String CN_RECYCLER_VIEW = "android.support.v7.widget.RecyclerView";
+ private static final String CN_LAYOUT_MANAGER = CN_RECYCLER_VIEW + "$LayoutManager";
+ private static final String CN_ADAPTER = CN_RECYCLER_VIEW + "$Adapter";
+
+ /**
+ * Tries to create an Adapter ({@code android.support.v7.widget.RecyclerView.Adapter} and a
+ * LayoutManager {@code RecyclerView.LayoutManager} and assign these to the {@code RecyclerView}
+ * that is passed.
+ * <p/>
+ * Any exceptions thrown during the process are logged in {@link Bridge#getLog()}
+ */
+ public static void setAdapter(@NonNull View recyclerView, @NonNull BridgeContext context,
+ @NonNull SessionParams params) {
+ try {
+ setLayoutManager(recyclerView, context, params.getProjectCallback());
+ Object adapter = createAdapter(params);
+ setProperty(recyclerView, CN_ADAPTER, adapter, "setAdapter");
+ } catch (ReflectionException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Error occured while trying to setup RecyclerView.", e, null);
+ }
+ }
+
+ private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context,
+ @NonNull IProjectCallback callback) throws ReflectionException {
+ Object cookie = context.getCookie(recyclerView);
+ assert cookie == null || cookie instanceof LayoutManagerType || cookie instanceof String;
+ if (!(cookie instanceof LayoutManagerType)) {
+ if (cookie != null) {
+ // TODO: When layoutlib API is updated, try to load the class with a null
+ // constructor or a constructor taking one argument - the context.
+ Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED,
+ "LayoutManager (" + cookie + ") not found, falling back to " +
+ "LinearLayoutManager", null);
+ }
+ cookie = LayoutManagerType.getDefault();
+ }
+ Object layoutManager = createLayoutManager((LayoutManagerType) cookie, context, callback);
+ setProperty(recyclerView, CN_LAYOUT_MANAGER, layoutManager, "setLayoutManager");
+ }
+
+ @Nullable
+ private static Object createLayoutManager(@Nullable LayoutManagerType type,
+ @NonNull Context context, @NonNull IProjectCallback callback)
+ throws ReflectionException {
+ if (type == null) {
+ type = LayoutManagerType.getDefault();
+ }
+ try {
+ return callback.loadView(type.getClassName(), type.getSignature(), type.getArgs(context));
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ @Nullable
+ private static Object createAdapter(@NonNull SessionParams params) throws ReflectionException {
+ Boolean ideSupport = params.getFlag(RenderParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT);
+ if (ideSupport != Boolean.TRUE) {
+ return null;
+ }
+ try {
+ return params.getProjectCallback().loadView(CN_ADAPTER, new Class[0], new Object[0]);
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ private static void setProperty(@NonNull View recyclerView, @NonNull String propertyClassName,
+ @Nullable Object propertyValue, @NonNull String propertySetter)
+ throws ReflectionException {
+ if (propertyValue != null) {
+ Class<?> layoutManagerClass = getClassInstance(propertyValue, propertyClassName);
+ Method setLayoutManager = getMethod(recyclerView.getClass(),
+ propertySetter, layoutManagerClass);
+ if (setLayoutManager != null) {
+ invoke(setLayoutManager, recyclerView, propertyValue);
+ }
+ }
+ }
+
+ /**
+ * Looks through the class hierarchy of {@code object} at runtime and returns the class matching
+ * the name {@code className}.
+ * <p/>
+ * This is used when we cannot use Class.forName() since the class we want was loaded from a
+ * different ClassLoader.
+ */
+ @NonNull
+ private static Class<?> getClassInstance(@NonNull Object object, @NonNull String className) {
+ Class<?> superClass = object.getClass();
+ while (superClass != null) {
+ if (className.equals(superClass.getName())) {
+ return superClass;
+ }
+ superClass = superClass.getSuperclass();
+ }
+ throw new RuntimeException("invalid object/classname combination.");
+ }
+
+ /** Supported LayoutManagers. */
+ public enum LayoutManagerType {
+ LINEAR_LAYOUT_MANGER("Linear",
+ "android.support.v7.widget.LinearLayoutManager",
+ new Class[]{Context.class}, new Object[]{CONTEXT}),
+ GRID_LAYOUT_MANAGER("Grid",
+ "android.support.v7.widget.GridLayoutManager",
+ new Class[]{Context.class, int.class}, new Object[]{CONTEXT, 2}),
+ STAGGERED_GRID_LAYOUT_MANAGER("StaggeredGrid",
+ "android.support.v7.widget.StaggeredGridLayoutManager",
+ new Class[]{int.class, int.class}, new Object[]{2, LinearLayout.VERTICAL});
+
+ private String mLogicalName;
+ private String mClassName;
+ private Class[] mSignature;
+ private Object[] mArgs;
+
+ LayoutManagerType(String logicalName, String className, Class[] signature, Object[] args) {
+ mLogicalName = logicalName;
+ mClassName = className;
+ mSignature = signature;
+ mArgs = args;
+ }
+
+ String getClassName() {
+ return mClassName;
+ }
+
+ Class[] getSignature() {
+ return mSignature;
+ }
+
+ @NonNull
+ Object[] getArgs(Context context) {
+ Object[] args = new Object[mArgs.length];
+ System.arraycopy(mArgs, 0, args, 0, mArgs.length);
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] == CONTEXT) {
+ args[i] = context;
+ }
+ }
+ return args;
+ }
+
+ @NonNull
+ public static LayoutManagerType getDefault() {
+ return LINEAR_LAYOUT_MANGER;
+ }
+
+ @Nullable
+ public static LayoutManagerType getByLogicalName(@NonNull String logicalName) {
+ for (LayoutManagerType type : values()) {
+ if (logicalName.equals(type.mLogicalName)) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ public static LayoutManagerType getByClassName(@NonNull String className) {
+ for (LayoutManagerType type : values()) {
+ if (className.equals(type.mClassName)) {
+ return type;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index 3a0321a167ca..c34f9b51a349 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -35,6 +35,7 @@ import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
+import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
@@ -615,8 +616,22 @@ public class GcSnapshot {
return;
}
- int width = layer.getImage().getWidth();
- int height = layer.getImage().getHeight();
+ int width;
+ int height;
+ Rectangle clipBounds = originalGraphics.getClipBounds();
+ if (clipBounds != null) {
+ if (clipBounds.width == 0 || clipBounds.height == 0) {
+ // Clip is 0 so no need to paint anything.
+ return;
+ }
+ // If we have clipBounds available, use them as they will always be
+ // smaller than the full layer size.
+ width = clipBounds.width;
+ height = clipBounds.height;
+ } else {
+ width = layer.getImage().getWidth();
+ height = layer.getImage().getHeight();
+ }
// Create a temporary image to which the color filter will be applied.
BufferedImage image = new BufferedImage(width, height,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 669e6b5d9865..3dee1e23dfe2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -16,20 +16,20 @@
package com.android.layoutlib.bridge.impl;
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
-
import com.android.ide.common.rendering.api.DrawableParams;
import com.android.ide.common.rendering.api.HardwareConfig;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.resources.ResourceType;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
import android.view.AttachInfo_Accessor;
import android.view.View.MeasureSpec;
import android.widget.FrameLayout;
@@ -38,7 +38,9 @@ import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
@@ -71,11 +73,37 @@ public class RenderDrawable extends RenderAction<DrawableParams> {
return Status.ERROR_NOT_A_DRAWABLE.createResult();
}
+ Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+
+ final Boolean allStates =
+ params.getFlag(RenderParamsFlags.FLAG_KEY_RENDER_ALL_DRAWABLE_STATES);
+ if (allStates == Boolean.TRUE) {
+ final List<BufferedImage> result;
+
+ if (d instanceof StateListDrawable) {
+ result = new ArrayList<BufferedImage>();
+ final StateListDrawable stateList = (StateListDrawable) d;
+ for (int i = 0; i < stateList.getStateCount(); i++) {
+ final Drawable stateDrawable = stateList.getStateDrawable(i);
+ result.add(renderImage(hardwareConfig, stateDrawable, context));
+ }
+ } else {
+ result = Collections.singletonList(renderImage(hardwareConfig, d, context));
+ }
+
+ return Status.SUCCESS.createResult(result);
+ } else {
+ BufferedImage image = renderImage(hardwareConfig, d, context);
+ return Status.SUCCESS.createResult(image);
+ }
+ }
+
+ private BufferedImage renderImage(HardwareConfig hardwareConfig, Drawable d,
+ BridgeContext context) {
// create a simple FrameLayout
FrameLayout content = new FrameLayout(context);
// get the actual Drawable object to draw
- Drawable d = ResourceHelper.getDrawable(drawableResource, context);
content.setBackground(d);
// set the AttachInfo on the root view.
@@ -83,8 +111,27 @@ public class RenderDrawable extends RenderAction<DrawableParams> {
// measure
- int w = hardwareConfig.getScreenWidth();
- int h = hardwareConfig.getScreenHeight();
+ int w = d.getIntrinsicWidth();
+ int h = d.getIntrinsicHeight();
+
+ final int screenWidth = hardwareConfig.getScreenWidth();
+ final int screenHeight = hardwareConfig.getScreenHeight();
+
+ if (w == -1 || h == -1) {
+ // Use screen size when either intrinsic width or height isn't available
+ w = screenWidth;
+ h = screenHeight;
+ } else if (w > screenWidth || h > screenHeight) {
+ // If image wouldn't fit to the screen, resize it to avoid cropping.
+
+ // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight
+ double scale = Math.min((double) screenWidth / w, (double) screenHeight / h);
+
+ // scale * w / scale * h = w / h, so, proportions are preserved.
+ w = (int) Math.floor(scale * w);
+ h = (int) Math.floor(scale * h);
+ }
+
int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
content.measure(w_spec, h_spec);
@@ -108,8 +155,7 @@ public class RenderDrawable extends RenderAction<DrawableParams> {
// and draw
content.draw(canvas);
-
- return Status.SUCCESS.createResult(image);
+ return image;
}
protected BufferedImage getImage(int w, int h) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 58acab9aa318..c9aa40010665 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -23,6 +23,8 @@ import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.HardwareConfig;
import com.android.ide.common.rendering.api.IAnimationListener;
@@ -50,7 +52,8 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
+import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
import com.android.layoutlib.bridge.bars.BridgeActionBar;
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
import com.android.layoutlib.bridge.bars.Config;
@@ -400,7 +403,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// it can instantiate the custom Fragment.
Fragment_Delegate.setProjectCallback(params.getProjectCallback());
- String rootTag = params.getFlag(SessionParamsFlags.FLAG_KEY_ROOT_TAG);
+ String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
boolean isPreference = "PreferenceScreen".equals(rootTag);
View view;
if (isPreference) {
@@ -551,7 +554,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// draw the views
// create the BufferedImage into which the layout will be rendered.
boolean newImage = false;
- if (newRenderSize || mCanvas == null) {
+
+ // When disableBitmapCaching is true, we do not reuse mImage and
+ // we create a new one in every render.
+ // This is useful when mImage is just a wrapper of Graphics2D so
+ // it doesn't get cached.
+ boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
+ RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
+ if (newRenderSize || mCanvas == null || disableBitmapCaching) {
if (params.getImageFactory() != null) {
mImage = params.getImageFactory().getImage(
mMeasuredScreenWidth,
@@ -578,8 +588,12 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
true /*isMutable*/, hardwareConfig.getDensity());
- // create a Canvas around the Android bitmap
- mCanvas = new Canvas(bitmap);
+ if (mCanvas == null) {
+ // create a Canvas around the Android bitmap
+ mCanvas = new Canvas(bitmap);
+ } else {
+ mCanvas.setBitmap(bitmap);
+ }
mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
}
@@ -1327,6 +1341,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
}
}
+ } else if (isInstanceOf(view, RecyclerViewUtil.CN_RECYCLER_VIEW)) {
+ RecyclerViewUtil.setAdapter(view, getContext(), getParams());
} else if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
@@ -1338,6 +1354,22 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
/**
+ * Check if the object is an instance of a class named {@code className}. This doesn't work
+ * for interfaces.
+ */
+ public static boolean isInstanceOf(Object object, String className) {
+ Class superClass = object.getClass();
+ while (superClass != null) {
+ String name = superClass.getName();
+ if (name.equals(className)) {
+ return true;
+ }
+ superClass = superClass.getSuperclass();
+ }
+ return false;
+ }
+
+ /**
* Sets up a {@link TabHost} object.
* @param tabHost the TabHost to setup.
* @param projectCallback The project callback object to access the project R class.
@@ -1494,6 +1526,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
* index 1 is with the offset.
*/
+ @NonNull
private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
ViewInfo[] result = new ViewInfo[2];
if (view == null) {
@@ -1589,6 +1622,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* The cookie for menu items are stored in menu item and not in the map from View stored in
* BridgeContext.
*/
+ @Nullable
private Object getViewKey(View view) {
BridgeContext context = getContext();
if (!(view instanceof MenuView.ItemView)) {
@@ -1611,7 +1645,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
return null;
}
- private void invalidateRenderingSize() {
+ public void invalidateRenderingSize() {
mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
new file mode 100644
index 000000000000..8e61edf90dcf
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 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 com.android.layoutlib.bridge.util;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Utility to convert checked Reflection exceptions to unchecked exceptions.
+ */
+public class ReflectionUtils {
+
+ @Nullable
+ public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name,
+ @Nullable Class<?>... params) throws ReflectionException {
+ try {
+ return clazz.getMethod(name, params);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ @Nullable
+ public static Object invoke(@NonNull Method method, @Nullable Object object,
+ @Nullable Object... args) throws ReflectionException {
+ Exception ex;
+ try {
+ return method.invoke(object, args);
+ } catch (IllegalAccessException e) {
+ ex = e;
+ } catch (InvocationTargetException e) {
+ ex = e;
+ }
+ throw new ReflectionException(ex);
+ }
+
+ /**
+ * Wraps all reflection related exceptions. Created since ReflectiveOperationException was
+ * introduced in 1.7 and we are still on 1.6
+ */
+ public static class ReflectionException extends Exception {
+ public ReflectionException() {
+ super();
+ }
+
+ public ReflectionException(String message) {
+ super(message);
+ }
+
+ public ReflectionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ReflectionException(Throwable cause) {
+ super(cause);
+ }
+ }
+}
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 98acd2f15657..f5e8292c2381 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
@@ -230,7 +230,6 @@ public final class CreateInfo implements ICreateInfo {
"android.os.SystemProperties",
"android.text.AndroidBidi",
"android.text.StaticLayout",
- "android.util.FloatMath",
"android.view.Display",
"libcore.icu.DateIntervalFormat",
"libcore.icu.ICU",
@@ -255,7 +254,6 @@ public final class CreateInfo implements ICreateInfo {
"android.view.SurfaceView", "android.view._Original_SurfaceView",
"android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
"android.webkit.WebView", "android.webkit._Original_WebView",
- "com.android.internal.policy.PolicyManager", "com.android.internal.policy._Original_PolicyManager",
};
/**
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index 9ff56d634c21..1b1f63ec41c4 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -13,7 +13,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
Main.cpp
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
#LOCAL_C_INCLUDES +=
@@ -36,10 +36,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE := pbkdf2gen
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
LOCAL_SRC_FILES := pbkdf2gen.cpp
LOCAL_LDLIBS += -ldl
-LOCAL_C_INCLUDES := external/openssl/include $(LOCAL_C_INCLUDES)
LOCAL_STATIC_LIBRARIES := libcrypto_static
include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp
index b2152e8f8468..64808c0a755f 100644
--- a/tools/obbtool/Main.cpp
+++ b/tools/obbtool/Main.cpp
@@ -89,7 +89,7 @@ void usage(void)
" Prints the OBB signature information of a file.\n\n", gProgName);
}
-void doAdd(const char* filename, struct PackageInfo* info) {
+void doAdd(const char* filename, PackageInfo* info) {
ObbFile *obb = new ObbFile();
if (obb->readFrom(filename)) {
fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename);
@@ -182,7 +182,7 @@ int main(int argc, char* const argv[])
{
int opt;
int option_index = 0;
- struct PackageInfo package_info;
+ PackageInfo package_info;
int result = 1; // pessimistically assume an error.