diff options
Diffstat (limited to 'tools')
26 files changed, 397 insertions, 213 deletions
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index 19532e8..5c11054 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -1856,9 +1856,18 @@ String8 AaptFile::getPrintableSource() const // ========================================================================= // ========================================================================= -status_t AaptGroup::addFile(const sp<AaptFile>& file) +status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate) { - if (mFiles.indexOfKey(file->getGroupEntry()) < 0) { + ssize_t index = mFiles.indexOfKey(file->getGroupEntry()); + if (index >= 0 && overwriteDuplicate) { + fprintf(stderr, "warning: overwriting '%s' with '%s'\n", + mFiles[index]->getSourceFile().string(), + file->getSourceFile().string()); + removeFile(index); + index = -1; + } + + if (index < 0) { file->mPath = mPath; mFiles.add(file->getGroupEntry(), file); return NO_ERROR; @@ -1964,7 +1973,8 @@ void AaptDir::removeDir(const String8& name) mDirs.removeItem(name); } -status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file) +status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file, + const bool overwrite) { sp<AaptGroup> group; if (mFiles.indexOfKey(leafName) >= 0) { @@ -1974,12 +1984,12 @@ status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file) mFiles.add(leafName, group); } - return group->addFile(file); + return group->addFile(file, overwrite); } ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, const AaptGroupEntry& kind, const String8& resType, - sp<FilePathStore>& fullResPaths) + sp<FilePathStore>& fullResPaths, const bool overwrite) { Vector<String8> fileNames; { @@ -2038,7 +2048,7 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, notAdded = true; } ssize_t res = subdir->slurpFullTree(bundle, pathName, kind, - resType, fullResPaths); + resType, fullResPaths, overwrite); if (res < NO_ERROR) { return res; } @@ -2048,7 +2058,7 @@ ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir, count += res; } else if (type == kFileTypeRegular) { sp<AaptFile> file = new AaptFile(pathName, kind, resType); - status_t err = addLeafFile(fileNames[i], file); + status_t err = addLeafFile(fileNames[i], file, overwrite); if (err != NO_ERROR) { return err; } @@ -2316,24 +2326,24 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) /* * If a directory of custom assets was supplied, slurp 'em up. */ - if (bundle->getAssetSourceDir()) { - const char* assetDir = bundle->getAssetSourceDir(); - - FileType type = getFileType(assetDir); + const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs(); + const int AN = assetDirs.size(); + for (int i = 0; i < AN; i++) { + FileType type = getFileType(assetDirs[i]); if (type == kFileTypeNonexistent) { - fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir); + fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]); return UNKNOWN_ERROR; } if (type != kFileTypeDirectory) { - fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir); + fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]); return UNKNOWN_ERROR; } - String8 assetRoot(assetDir); + String8 assetRoot(assetDirs[i]); sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir)); AaptGroupEntry group; count = assetAaptDir->slurpFullTree(bundle, assetRoot, group, - String8(), mFullAssetPaths); + String8(), mFullAssetPaths, true); if (count < 0) { totalCount = count; goto bail; @@ -2343,9 +2353,10 @@ ssize_t AaptAssets::slurpFromArgs(Bundle* bundle) } totalCount += count; - if (bundle->getVerbose()) + if (bundle->getVerbose()) { printf("Found %d custom asset file%s in %s\n", - count, (count==1) ? "" : "s", assetDir); + count, (count==1) ? "" : "s", assetDirs[i]); + } } /* diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 9733b6d..336d08b 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -299,7 +299,7 @@ public: const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& getFiles() const { return mFiles; } - status_t addFile(const sp<AaptFile>& file); + status_t addFile(const sp<AaptFile>& file, const bool overwriteDuplicate=false); void removeFile(size_t index); void print(const String8& prefix) const; @@ -365,12 +365,14 @@ private: status_t addDir(const String8& name, const sp<AaptDir>& dir); sp<AaptDir> makeDir(const String8& name); status_t addLeafFile(const String8& leafName, - const sp<AaptFile>& file); + const sp<AaptFile>& file, + const bool overwrite=false); virtual ssize_t slurpFullTree(Bundle* bundle, const String8& srcDir, const AaptGroupEntry& kind, const String8& resType, - sp<FilePathStore>& fullResPaths); + sp<FilePathStore>& fullResPaths, + const bool overwrite=false); String8 mLeaf; String8 mPath; diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index 5089b9d..26b10a6 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -55,7 +55,6 @@ public: mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL), mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL), mAutoAddOverlay(false), mGenDependencies(false), - mAssetSourceDir(NULL), mCrunchedOutputDir(NULL), mProguardFile(NULL), mAndroidManifestFile(NULL), mPublicOutputFile(NULL), mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), @@ -123,8 +122,8 @@ public: /* * Input options. */ - const char* getAssetSourceDir() const { return mAssetSourceDir; } - void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; } + const android::Vector<const char*>& getAssetSourceDirs() const { return mAssetSourceDirs; } + void addAssetSourceDir(const char* dir) { mAssetSourceDirs.insertAt(dir,0); } const char* getCrunchedOutputDir() const { return mCrunchedOutputDir; } void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; } const char* getProguardFile() const { return mProguardFile; } @@ -272,6 +271,7 @@ private: android::Vector<const char*> mPackageIncludes; android::Vector<const char*> mJarFiles; android::Vector<const char*> mNoCompressExtensions; + android::Vector<const char*> mAssetSourceDirs; android::Vector<const char*> mResourceSourceDirs; const char* mManifestMinSdkVersion; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index c7cce96..3c27a19 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -1897,7 +1897,7 @@ int doPackage(Bundle* bundle) N = bundle->getFileSpecCount(); if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0 - && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) { + && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) { fprintf(stderr, "ERROR: no input files\n"); goto bail; } diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index 977226b..d1d3deb 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -345,7 +345,7 @@ int main(int argc, char* const argv[]) goto bail; } convertPath(argv[0]); - bundle.setAssetSourceDir(argv[0]); + bundle.addAssetSourceDir(argv[0]); break; case 'G': argc--; diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk index ed497a5..1fa9615 100644 --- a/tools/layoutlib/Android.mk +++ b/tools/layoutlib/Android.mk @@ -33,6 +33,8 @@ built_core_classes := $(call java-lib-files,core) built_ext_dep := $(call java-lib-deps,ext) built_ext_classes := $(call java-lib-files,ext) +built_ext_data := $(call intermediates-dir-for, \ + JAVA_LIBRARIES,ext,,COMMON)/javalib.jar built_layoutlib_create_jar := $(call intermediates-dir-for, \ JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar @@ -60,7 +62,8 @@ $(LOCAL_BUILT_MODULE): $(built_core_dep) \ $@ \ $(built_core_classes) \ $(built_framework_classes) \ - $(built_ext_classes) + $(built_ext_classes) \ + $(built_ext_data) $(hide) ls -l $(built_framework_classes) diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java index 62d0a0d..802cf1c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java +++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java @@ -20,6 +20,7 @@ import java.awt.Font; import java.awt.Graphics2D; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; +import java.awt.geom.Rectangle2D; import java.util.LinkedList; import java.util.List; @@ -50,9 +51,12 @@ public class BidiRenderer { } } - /* package */ Graphics2D graphics; - /* package */ Paint_Delegate paint; - /* package */ char[] text; + private Graphics2D mGraphics; + private Paint_Delegate mPaint; + private char[] mText; + // Bounds of the text drawn so far. + private RectF mBounds; + private float mBaseline; /** * @param graphics May be null. @@ -61,9 +65,9 @@ public class BidiRenderer { */ /* package */ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) { assert (paint != null); - this.graphics = graphics; - this.paint = paint; - this.text = text; + mGraphics = graphics; + mPaint = paint; + mText = text; } /** @@ -77,61 +81,62 @@ public class BidiRenderer { * @param advances If not null, then advances for each character to be rendered are returned * here. * @param advancesIndex index into advances from where the advances need to be filled. - * @param draw If true and {@link graphics} is not null, draw the rendered text on the graphics + * @param draw If true and {@code graphics} is not null, draw the rendered text on the graphics * at the given co-ordinates * @param x The x-coordinate of the left edge of where the text should be drawn on the given * graphics. - * @param y The y-coordinate at which to draw the text on the given graphics. - * @return The x-coordinate of the right edge of the drawn text. In other words, - * x + the width of the text. + * @param y The y-coordinate at which to draw the text on the given mGraphics. + * @return A rectangle specifying the bounds of the text drawn. */ - /* package */ float renderText(int start, int limit, boolean isRtl, float advances[], + /* package */ RectF renderText(int start, int limit, boolean isRtl, float[] advances, int advancesIndex, boolean draw, float x, float y) { // We break the text into scripts and then select font based on it and then render each of // the script runs. - for (ScriptRun run : getScriptRuns(text, start, limit, isRtl, paint.getFonts())) { + mBounds = new RectF(x, y, x, y); + mBaseline = y; + for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mPaint.getFonts())) { int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT; flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT; - x = renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw, - x, y); + renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw); advancesIndex += run.limit - run.start; } - return x; + return mBounds; } /** - * Render a script run. Use the preferred font to render as much as possible. This also - * implements a fallback mechanism to render characters that cannot be drawn using the - * preferred font. - * - * @return x + width of the text drawn. + * Render a script run to the right of the bounds passed. Use the preferred font to render as + * much as possible. This also implements a fallback mechanism to render characters that cannot + * be drawn using the preferred font. */ - private float renderScript(int start, int limit, FontInfo preferredFont, int flag, - float advances[], int advancesIndex, boolean draw, float x, float y) { - List<FontInfo> fonts = paint.getFonts(); + private void renderScript(int start, int limit, FontInfo preferredFont, int flag, + float[] advances, int advancesIndex, boolean draw) { + List<FontInfo> fonts = mPaint.getFonts(); if (fonts == null || preferredFont == null) { - return x; + return; } while (start < limit) { boolean foundFont = false; - int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(text, start, limit); + int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(mText, start, limit); if (canDisplayUpTo == -1) { - return render(start, limit, preferredFont, flag, advances, advancesIndex, draw, - x, y); - } else if (canDisplayUpTo > start) { // can draw something - x = render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex, - draw, x, y); + // We can draw all characters in the text. + render(start, limit, preferredFont, flag, advances, advancesIndex, draw); + return; + } + if (canDisplayUpTo > start) { + // We can draw something. + render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex, draw); advancesIndex += canDisplayUpTo - start; start = canDisplayUpTo; } - int charCount = Character.isHighSurrogate(text[start]) ? 2 : 1; + // The current character cannot be drawn with the preferred font. Cycle through all the + // fonts to check which one can draw it. + int charCount = Character.isHighSurrogate(mText[start]) ? 2 : 1; for (FontInfo font : fonts) { - canDisplayUpTo = font.mFont.canDisplayUpTo(text, start, start + charCount); + canDisplayUpTo = font.mFont.canDisplayUpTo(mText, start, start + charCount); if (canDisplayUpTo == -1) { - x = render(start, start+charCount, font, flag, advances, advancesIndex, draw, - x, y); + render(start, start+charCount, font, flag, advances, advancesIndex, draw); start += charCount; advancesIndex += charCount; foundFont = true; @@ -143,46 +148,63 @@ public class BidiRenderer { // probably appear as a box or a blank space. We could, probably, use some // heuristics and break the character into the base character and diacritics and // then draw it, but it's probably not worth the effort. - x = render(start, start + charCount, preferredFont, flag, advances, advancesIndex, - draw, x, y); + render(start, start + charCount, preferredFont, flag, advances, advancesIndex, + draw); start += charCount; advancesIndex += charCount; } } - return x; } /** - * Render the text with the given font. + * Renders the text to the right of the bounds with the given font. + * @param font The font to render the text with. */ - private float render(int start, int limit, FontInfo font, int flag, float advances[], - int advancesIndex, boolean draw, float x, float y) { + private void render(int start, int limit, FontInfo font, int flag, float[] advances, + int advancesIndex, boolean draw) { - float totalAdvance = 0; // Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with // the anti-aliasing set. FontRenderContext f = font.mMetrics.getFontRenderContext(); - FontRenderContext frc = new FontRenderContext(f.getTransform(), paint.isAntiAliased(), + FontRenderContext frc = new FontRenderContext(f.getTransform(), mPaint.isAntiAliased(), f.usesFractionalMetrics()); - GlyphVector gv = font.mFont.layoutGlyphVector(frc, text, start, limit, flag); + GlyphVector gv = font.mFont.layoutGlyphVector(frc, mText, start, limit, flag); int ng = gv.getNumGlyphs(); int[] ci = gv.getGlyphCharIndices(0, ng, null); - for (int i = 0; i < ng; i++) { - float adv = gv.getGlyphMetrics(i).getAdvanceX(); - if (advances != null) { + if (advances != null) { + for (int i = 0; i < ng; i++) { int adv_idx = advancesIndex + ci[i]; - advances[adv_idx] += adv; + advances[adv_idx] += gv.getGlyphMetrics(i).getAdvanceX(); } - totalAdvance += adv; } - if (draw && graphics != null) { - graphics.drawGlyphVector(gv, x, y); + if (draw && mGraphics != null) { + mGraphics.drawGlyphVector(gv, mBounds.right, mBaseline); + } + + // Update the bounds. + Rectangle2D awtBounds = gv.getLogicalBounds(); + RectF bounds = awtRectToAndroidRect(awtBounds, mBounds.right, mBaseline); + // If the width of the bounds is zero, no text had been drawn earlier. Hence, use the + // coordinates from the bounds as an offset. + if (Math.abs(mBounds.right - mBounds.left) == 0) { + mBounds = bounds; + } else { + mBounds.union(bounds); } - return x + totalAdvance; } // --- Static helper methods --- + private static RectF awtRectToAndroidRect(Rectangle2D awtRec, float offsetX, float offsetY) { + float left = (float) awtRec.getX(); + float top = (float) awtRec.getY(); + float right = (float) (left + awtRec.getWidth()); + float bottom = (float) (top + awtRec.getHeight()); + RectF androidRect = new RectF(left, top, right, bottom); + androidRect.offset(offsetX, offsetY); + return androidRect; + } + /* package */ static List<ScriptRun> getScriptRuns(char[] text, int start, int limit, boolean isRtl, List<FontInfo> fonts) { LinkedList<ScriptRun> scriptRuns = new LinkedList<ScriptRun>(); diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java index f5c4677..06673c1 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java @@ -44,62 +44,13 @@ import java.util.Set; */ /*package*/ class BitmapFactory_Delegate { - // ------ Java delegates ------ - - @LayoutlibDelegate - /*package*/ static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) { - if (bm == null || opts == null) { - return bm; - } - - final int density = opts.inDensity; - if (density == 0) { - return bm; - } - - bm.setDensity(density); - final int targetDensity = opts.inTargetDensity; - if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) { - return bm; - } - - byte[] np = bm.getNinePatchChunk(); - final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np); - // DELEGATE CHANGE: never scale 9-patch - if (opts.inScaled && isNinePatch == false) { - float scale = targetDensity / (float)density; - // TODO: This is very inefficient and should be done in native by Skia - final Bitmap oldBitmap = bm; - bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f), - (int) (bm.getHeight() * scale + 0.5f), true); - oldBitmap.recycle(); - - if (isNinePatch) { - np = nativeScaleNinePatch(np, scale, outPadding); - bm.setNinePatchChunk(np); - } - bm.setDensity(targetDensity); - } - - return bm; - } - - // ------ Native Delegates ------ @LayoutlibDelegate /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage, Rect padding, Options opts) { - return nativeDecodeStream(is, storage, padding, opts, false, 1.f); - } - - @LayoutlibDelegate - /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage, - Rect padding, Options opts, boolean applyScale, float scale) { Bitmap bm = null; - //TODO support rescaling - Density density = Density.MEDIUM; Set<BitmapCreateFlags> bitmapCreateFlags = EnumSet.of(BitmapCreateFlags.MUTABLE); if (opts != null) { @@ -157,13 +108,6 @@ import java.util.Set; } @LayoutlibDelegate - /*package*/ static Bitmap nativeDecodeAsset(long asset, Rect padding, Options opts, - boolean applyScale, float scale) { - opts.inBitmap = null; - return null; - } - - @LayoutlibDelegate /*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset, int length, Options opts) { opts.inBitmap = null; @@ -171,13 +115,6 @@ import java.util.Set; } @LayoutlibDelegate - /*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) { - // don't scale for now. This should not be called anyway since we re-implement - // BitmapFactory.finishDecode(); - return chunk; - } - - @LayoutlibDelegate /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) { return true; } diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index f6abaa1..89d7e23 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -314,6 +314,13 @@ public final class Bitmap_Delegate { } @LayoutlibDelegate + /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height, + int config, int allocSize) { + Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, + "Bitmap.reconfigure() is not supported", null /*data*/); + } + + @LayoutlibDelegate /*package*/ static boolean nativeCompress(long nativeBitmap, int format, int quality, OutputStream stream, byte[] tempStorage) { Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, @@ -342,28 +349,6 @@ public final class Bitmap_Delegate { } @LayoutlibDelegate - /*package*/ static int nativeWidth(long nativeBitmap) { - // get the delegate from the native int. - Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); - if (delegate == null) { - return 0; - } - - return delegate.mImage.getWidth(); - } - - @LayoutlibDelegate - /*package*/ static int nativeHeight(long nativeBitmap) { - // get the delegate from the native int. - Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); - if (delegate == null) { - return 0; - } - - return delegate.mImage.getHeight(); - } - - @LayoutlibDelegate /*package*/ static int nativeRowBytes(long nativeBitmap) { // get the delegate from the native int. Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); @@ -408,19 +393,21 @@ public final class Bitmap_Delegate { } @LayoutlibDelegate - /*package*/ static int nativeGetPixel(long nativeBitmap, int x, int y) { + /*package*/ static int nativeGetPixel(long nativeBitmap, int x, int y, + boolean isPremultiplied) { // get the delegate from the native int. Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); if (delegate == null) { return 0; } + // TODO: Support isPremultiplied. return delegate.mImage.getRGB(x, y); } @LayoutlibDelegate /*package*/ static void nativeGetPixels(long nativeBitmap, int[] pixels, int offset, - int stride, int x, int y, int width, int height) { + int stride, int x, int y, int width, int height, boolean isPremultiplied) { Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); if (delegate == null) { return; @@ -431,7 +418,8 @@ public final class Bitmap_Delegate { @LayoutlibDelegate - /*package*/ static void nativeSetPixel(long nativeBitmap, int x, int y, int color) { + /*package*/ static void nativeSetPixel(long nativeBitmap, int x, int y, int color, + boolean isPremultiplied) { Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); if (delegate == null) { return; @@ -442,7 +430,7 @@ public final class Bitmap_Delegate { @LayoutlibDelegate /*package*/ static void nativeSetPixels(long nativeBitmap, int[] colors, int offset, - int stride, int x, int y, int width, int height) { + int stride, int x, int y, int width, int height, boolean isPremultiplied) { Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); if (delegate == null) { return; diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 3111f0d..73d274c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -989,7 +989,8 @@ public final class Canvas_Delegate { int limit = index + count; boolean isRtl = flags == Canvas.DIRECTION_RTL; if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { - float m = paintDelegate.measureText(text, index, count, isRtl); + RectF bounds = paintDelegate.measureText(text, index, count, isRtl); + float m = bounds.right - bounds.left; if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { x -= m / 2; } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java index a5c52e5..74b2893 100644 --- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java @@ -167,6 +167,7 @@ public final class NinePatch_Delegate { return sManager.addNewDelegate(newDelegate); } + @LayoutlibDelegate /*package*/ static void nativeFinalize(long chunk) { sManager.removeJavaReferenceFor(chunk); } @@ -175,7 +176,7 @@ public final class NinePatch_Delegate { /*package*/ static void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance, long chunk, long paint_instance_or_null, int destDensity, int srcDensity) { draw(canvas_instance, - (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(), + (int) loc.left, (int) loc.top, (int) loc.right, (int) loc.bottom, bitmap_instance, chunk, paint_instance_or_null, destDensity, srcDensity); } @@ -184,7 +185,7 @@ public final class NinePatch_Delegate { /*package*/ static void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance, long chunk, long paint_instance_or_null, int destDensity, int srcDensity) { draw(canvas_instance, - loc.left, loc.top, loc.width(), loc.height(), + loc.left, loc.top, loc.right, loc.bottom, bitmap_instance, chunk, paint_instance_or_null, destDensity, srcDensity); } diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index ca8e8aa..7007b71 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -575,7 +575,8 @@ public class Paint_Delegate { return 0; } - return delegate.measureText(text, index, count, isRtl(bidiFlags)); + RectF bounds = delegate.measureText(text, index, count, isRtl(bidiFlags)); + return bounds.right - bounds.left; } @LayoutlibDelegate @@ -614,7 +615,8 @@ public class Paint_Delegate { } // measure from start to end - float res = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags)); + RectF bounds = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags)); + float res = bounds.right - bounds.left; if (measuredWidth != null) { measuredWidth[measureIndex] = res; @@ -991,8 +993,9 @@ public class Paint_Delegate { boolean isRtl = isRtl(flags); int limit = index + count; - return new BidiRenderer(null, delegate, text).renderText( + RectF bounds = new BidiRenderer(null, delegate, text).renderText( index, limit, isRtl, advances, advancesIndex, false, 0, 0); + return bounds.right - bounds.left; } @LayoutlibDelegate @@ -1058,9 +1061,7 @@ public class Paint_Delegate { if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) { return; } - int w = (int) delegate.measureText(text, index, count, isRtl(bidiFlags)); - int h= delegate.getFonts().get(0).mMetrics.getHeight(); - bounds.set(0, 0, w, h); + delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds); } @LayoutlibDelegate @@ -1154,7 +1155,7 @@ public class Paint_Delegate { } } - /*package*/ float measureText(char[] text, int index, int count, boolean isRtl) { + /*package*/ RectF measureText(char[] text, int index, int count, boolean isRtl) { return new BidiRenderer(null, this, text).renderText( index, index + count, isRtl, null, 0, false, 0, 0); } diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java index f3b56d9..4e9c129 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java @@ -474,6 +474,12 @@ public final class Path_Delegate { } @LayoutlibDelegate + /*package*/ static boolean native_op(long nPath1, long nPath2, int op, int result) { + Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.op() not supported", null); + return false; + } + + @LayoutlibDelegate /*package*/ static void finalizer(long nPath) { sManager.removeJavaReferenceFor(nPath); } diff --git a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java index 15cd687..320dd0d 100644 --- a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java +++ b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java @@ -17,6 +17,7 @@ package android.text.format; import java.util.Calendar; +import java.util.TimeZone; import java.util.UnknownFormatConversionException; import java.util.regex.Pattern; @@ -35,6 +36,28 @@ public class Time_Delegate { // Regex to match odd number of '%'. private static final Pattern p = Pattern.compile("(?<!%)(%%)*%(?!%)"); + // Format used by toString() + private static final String FORMAT = "%1$tY%1$tm%1$tdT%1$tH%1$tM%1$tS<%1$tZ>"; + + @LayoutlibDelegate + /*package*/ static long normalize(Time thisTime, boolean ignoreDst) { + long millis = toMillis(thisTime, ignoreDst); + set(thisTime, millis); + return millis; + } + + @LayoutlibDelegate + /*package*/ static void switchTimezone(Time thisTime, String timezone) { + Calendar c = timeToCalendar(thisTime); + c.setTimeZone(TimeZone.getTimeZone(timezone)); + calendarToTime(c, thisTime); + } + + @LayoutlibDelegate + /*package*/ static int nativeCompare(Time a, Time b) { + return timeToCalendar(a).compareTo(timeToCalendar(b)); + } + @LayoutlibDelegate /*package*/ static String format1(Time thisTime, String format) { @@ -46,16 +69,92 @@ public class Time_Delegate { // of $. return String.format( p.matcher(format).replaceAll("$0\\1\\$t"), - timeToCalendar(thisTime, Calendar.getInstance())); + timeToCalendar(thisTime)); } catch (UnknownFormatConversionException e) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_STRFTIME, "Unrecognized format", e, format); return format; } } - private static Calendar timeToCalendar(Time time, Calendar calendar) { + /** + * Return the current time in YYYYMMDDTHHMMSS<tz> format + */ + @LayoutlibDelegate + /*package*/ static String toString(Time thisTime) { + Calendar c = timeToCalendar(thisTime); + return String.format(FORMAT, c); + } + + @LayoutlibDelegate + /*package*/ static boolean nativeParse(Time thisTime, String s) { + Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, + "android.text.format.Time.parse() not supported.", null); + return false; + } + + @LayoutlibDelegate + /*package*/ static boolean nativeParse3339(Time thisTime, String s) { + Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, + "android.text.format.Time.parse3339() not supported.", null); + return false; + } + + @LayoutlibDelegate + /*package*/ static void setToNow(Time thisTime) { + calendarToTime(getCalendarInstance(thisTime), thisTime); + } + + @LayoutlibDelegate + /*package*/ static long toMillis(Time thisTime, boolean ignoreDst) { + // TODO: Respect ignoreDst. + return timeToCalendar(thisTime).getTimeInMillis(); + } + + @LayoutlibDelegate + /*package*/ static void set(Time thisTime, long millis) { + Calendar c = getCalendarInstance(thisTime); + c.setTimeInMillis(millis); + calendarToTime(c,thisTime); + } + + @LayoutlibDelegate + /*package*/ static String format2445(Time thisTime) { + Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, + "android.text.format.Time.format2445() not supported.", null); + return ""; + } + + // ---- private helper methods ---- + + private static Calendar timeToCalendar(Time time) { + Calendar calendar = getCalendarInstance(time); calendar.set(time.year, time.month, time.monthDay, time.hour, time.minute, time.second); return calendar; } + private static void calendarToTime(Calendar c, Time time) { + time.timezone = c.getTimeZone().getID(); + time.set(c.get(Calendar.SECOND), c.get(Calendar.MINUTE), c.get(Calendar.HOUR_OF_DAY), + c.get(Calendar.DATE), c.get(Calendar.MONTH), c.get(Calendar.YEAR)); + time.weekDay = c.get(Calendar.DAY_OF_WEEK); + time.yearDay = c.get(Calendar.DAY_OF_YEAR); + time.isDst = c.getTimeZone().inDaylightTime(c.getTime()) ? 1 : 0; + // gmtoff is in seconds and TimeZone.getOffset() returns milliseconds. + time.gmtoff = c.getTimeZone().getOffset(c.getTimeInMillis()) / DateUtils.SECOND_IN_MILLIS; + } + + /** + * Return a calendar instance with the correct timezone. + * + * @param time Time to obtain the timezone from. + */ + private static Calendar getCalendarInstance(Time time) { + // TODO: Check platform code to make sure the behavior is same for null/invalid timezone. + if (time == null || time.timezone == null) { + // Default to local timezone. + return Calendar.getInstance(); + } + // If timezone is invalid, use GMT. + return Calendar.getInstance(TimeZone.getTimeZone(time.timezone)); + } } 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 57771e3..377d996 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 @@ -334,7 +334,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { backgroundView = backgroundLayout; backgroundLayout.setOrientation(LinearLayout.VERTICAL); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + LayoutParams.MATCH_PARENT, 0); layoutParams.weight = 1; backgroundLayout.setLayoutParams(layoutParams); topLayout.addView(backgroundLayout); @@ -369,7 +369,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { // content frame mContentRoot = new FrameLayout(context); layoutParams = new LinearLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + LayoutParams.MATCH_PARENT, 0); layoutParams.weight = 1; mContentRoot.setLayoutParams(layoutParams); backgroundLayout.addView(mContentRoot); diff --git a/tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java index a773d93..d94c205 100644 --- a/tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java +++ b/tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java @@ -21,6 +21,7 @@ import java.text.FieldPosition; import com.android.ide.common.rendering.api.LayoutLog; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import com.ibm.icu.text.DateIntervalFormat; import com.ibm.icu.util.DateInterval; import com.ibm.icu.util.TimeZone; @@ -38,6 +39,7 @@ public class DateIntervalFormat_Delegate { // ---- native methods ---- + @LayoutlibDelegate /*package*/static String formatDateInterval(long address, long fromDate, long toDate) { DateIntervalFormat_Delegate delegate = sManager.getDelegate((int)address); if (delegate == null) { @@ -52,6 +54,7 @@ public class DateIntervalFormat_Delegate { return sb.toString(); } + @LayoutlibDelegate /*package*/ static long createDateIntervalFormat(String skeleton, String localeName, String tzName) { TimeZone prevDefaultTz = TimeZone.getDefault(); @@ -63,6 +66,7 @@ public class DateIntervalFormat_Delegate { return sManager.addNewDelegate(newDelegate); } + @LayoutlibDelegate /*package*/ static void destroyDateIntervalFormat(long address) { sManager.removeJavaReferenceFor((int)address); } diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java index 06ae804..ad4103b 100644 --- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java +++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java @@ -46,7 +46,7 @@ public class ICU_Delegate { // --- Native methods accessing ICU's database. @LayoutlibDelegate - /*package*/ static String getBestDateTimePattern(String skeleton, String localeName) { + /*package*/ static String getBestDateTimePatternNative(String skeleton, String localeName) { return DateTimePatternGenerator.getInstance(new ULocale(localeName)) .getBestPattern(skeleton); } @@ -167,7 +167,7 @@ public class ICU_Delegate { } @LayoutlibDelegate - /*package*/ static boolean initLocaleDataImpl(String locale, LocaleData result) { + /*package*/ static boolean initLocaleDataNative(String locale, LocaleData result) { // Used by Calendar. result.firstDayOfWeek = Integer.valueOf(1); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java index 1572a40..9a31705 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java @@ -29,6 +29,7 @@ import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; @@ -60,6 +61,9 @@ public class AsmAnalyzer { private final String[] mIncludeGlobs; /** The set of classes to exclude.*/ private final Set<String> mExcludedClasses; + /** Glob patterns of files to keep as is. */ + private final String[] mIncludeFileGlobs; + /** Copy these files into the output as is. */ /** * Creates a new analyzer. @@ -70,15 +74,19 @@ public class AsmAnalyzer { * @param deriveFrom Keep all classes that derive from these one (these included). * @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*" * ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is) + * @param includeFileGlobs Glob patterns of files which are kept as is. This is only for files + * not ending in .class. */ public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen, - String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses) { + String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses, + String[] includeFileGlobs) { mLog = log; mGen = gen; mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>(); mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0]; mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0]; mExcludedClasses = excludeClasses; + mIncludeFileGlobs = includeFileGlobs != null ? includeFileGlobs : new String[0]; } /** @@ -86,7 +94,11 @@ public class AsmAnalyzer { * Fills the generator with classes & dependencies found. */ public void analyze() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar); + + TreeMap<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); + Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + + parseZip(mOsSourceJar, zipClasses, filesFound); mLog.info("Found %d classes in input JAR%s.", zipClasses.size(), mOsSourceJar.size() > 1 ? "s" : ""); @@ -96,15 +108,29 @@ public class AsmAnalyzer { if (mGen != null) { mGen.setKeep(found); mGen.setDeps(deps); + mGen.setCopyFiles(filesFound); } } /** - * Parses a JAR file and returns a list of all classes founds using a map - * class name => ASM ClassReader. Class names are in the form "android.view.View". + * Parses a JAR file and adds all the classes found to <code>classes</code> + * and all other files to <code>filesFound</code>. + * + * @param classes The map of class name => ASM ClassReader. Class names are + * in the form "android.view.View". + * @param fileFound The map of file name => InputStream. The file name is + * in the form "android/data/dataFile". */ - Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException { - TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>(); + void parseZip(List<String> jarPathList, Map<String, ClassReader> classes, + Map<String, InputStream> filesFound) throws IOException { + if (classes == null || filesFound == null) { + return; + } + + Pattern[] includeFilePatterns = new Pattern[mIncludeFileGlobs.length]; + for (int i = 0; i < mIncludeFileGlobs.length; ++i) { + includeFilePatterns[i] = getPatternFromGlob(mIncludeFileGlobs[i]); + } for (String jarPath : jarPathList) { ZipFile zip = new ZipFile(jarPath); @@ -116,11 +142,17 @@ public class AsmAnalyzer { ClassReader cr = new ClassReader(zip.getInputStream(entry)); String className = classReaderToClassName(cr); classes.put(className, cr); + } else { + for (int i = 0; i < includeFilePatterns.length; ++i) { + if (includeFilePatterns[i].matcher(entry.getName()).matches()) { + filesFound.put(entry.getName(), zip.getInputStream(entry)); + break; + } + } } } } - return classes; } /** @@ -202,7 +234,19 @@ public class AsmAnalyzer { */ void findGlobs(String globPattern, Map<String, ClassReader> zipClasses, Map<String, ClassReader> inOutFound) throws LogAbortException { - // transforms the glob pattern in a regexp: + + Pattern regexp = getPatternFromGlob(globPattern); + + for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { + String class_name = entry.getKey(); + if (regexp.matcher(class_name).matches()) { + findClass(class_name, zipClasses, inOutFound); + } + } + } + + Pattern getPatternFromGlob(String globPattern) { + // transforms the glob pattern in a regexp: // - escape "." with "\." // - replace "*" by "[^.]*" // - escape "$" with "\$" @@ -216,14 +260,7 @@ public class AsmAnalyzer { globPattern = globPattern.replaceAll("@", ".*"); globPattern += "$"; - Pattern regexp = Pattern.compile(globPattern); - - for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { - String class_name = entry.getKey(); - if (regexp.matcher(class_name).matches()) { - findClass(class_name, zipClasses, inOutFound); - } - } + return Pattern.compile(globPattern); } /** diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java index b102561..207d8ae 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java @@ -20,6 +20,7 @@ import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; +import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -52,6 +53,8 @@ public class AsmGenerator { private Map<String, ClassReader> mKeep; /** All dependencies that must be completely stubbed. */ private Map<String, ClassReader> mDeps; + /** All files that are to be copied as-is. */ + private Map<String, InputStream> mCopyFiles; /** Counter of number of classes renamed during transform. */ private int mRenameCount; /** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */ @@ -195,6 +198,11 @@ public class AsmGenerator { mDeps = deps; } + /** Sets the map of files to output as-is. */ + public void setCopyFiles(Map<String, InputStream> copyFiles) { + mCopyFiles = copyFiles; + } + /** Gets the map of classes to output as-is, except if they have native methods */ public Map<String, ClassReader> getKeep() { return mKeep; @@ -205,6 +213,11 @@ public class AsmGenerator { return mDeps; } + /** Gets the map of files to output as-is. */ + public Map<String, InputStream> getCopyFiles() { + return mCopyFiles; + } + /** Generates the final JAR */ public void generate() throws FileNotFoundException, IOException { TreeMap<String, byte[]> all = new TreeMap<String, byte[]>(); @@ -232,6 +245,15 @@ public class AsmGenerator { all.put(name, b); } + for (Entry<String, InputStream> entry : mCopyFiles.entrySet()) { + try { + byte[] b = inputStreamToByteArray(entry.getValue()); + all.put(entry.getKey(), b); + } catch (IOException e) { + // Ignore. + } + + } mLog.info("# deps classes: %d", mDeps.size()); mLog.info("# keep classes: %d", mKeep.size()); mLog.info("# renamed : %d", mRenameCount); @@ -381,4 +403,13 @@ public class AsmGenerator { return cv.hasNativeMethods(); } + private byte[] inputStreamToByteArray(InputStream is) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + byte[] data = new byte[8192]; // 8KB + int n; + while ((n = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, n); + } + return buffer.toByteArray(); + } } 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 f6779e3..79aa642 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 @@ -131,7 +131,6 @@ public final class CreateInfo implements ICreateInfo { "android.os.HandlerThread#run", "android.os.Build#getString", "android.text.format.DateFormat#is24HourFormat", - "android.text.format.Time#format1", "android.view.Choreographer#getRefreshRate", "android.view.Display#updateDisplayInfoLocked", "android.view.LayoutInflater#rInflate", @@ -188,6 +187,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.Xfermode", "android.os.SystemClock", "android.text.AndroidBidi", + "android.text.format.Time", "android.util.FloatMath", "android.view.Display", "libcore.icu.DateIntervalFormat", diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java index ee501d2..a79fba1 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java @@ -115,7 +115,10 @@ public class Main { "android.database.ContentObserver", // for Digital clock "com.android.i18n.phonenumbers.*", // for TextView with autolink attribute }, - excludeClasses); + excludeClasses, + new String[] { + "com/android/i18n/phonenumbers/data/*", + }); aa.analyze(); agen.generate(); diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java index 005fc9d..7ec0d38 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java @@ -29,6 +29,7 @@ import org.junit.Test; import org.objectweb.asm.ClassReader; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; @@ -55,8 +56,10 @@ public class AsmAnalyzerTest { Set<String> excludeClasses = new HashSet<String>(1); excludeClasses.add("java.lang.JavaClass"); - mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, - null /* deriveFrom */, null /* includeGlobs */, excludeClasses); + + String[] includeFiles = new String[]{"mock_android/data/data*"}; + mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */, + null /* includeGlobs */, excludeClasses, includeFiles); } @After @@ -65,7 +68,11 @@ public class AsmAnalyzerTest { @Test public void testParseZip() throws IOException { - Map<String, ClassReader> map = mAa.parseZip(mOsJarPath); + + Map<String, ClassReader> map = new TreeMap<String, ClassReader>(); + Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + + mAa.parseZip(mOsJarPath, map, filesFound); assertArrayEquals(new String[] { "java.lang.JavaClass", @@ -86,11 +93,17 @@ public class AsmAnalyzerTest { "mock_android.widget.TableLayout$LayoutParams" }, map.keySet().toArray()); + assertArrayEquals(new String[] {"mock_android/data/dataFile"}, + filesFound.keySet().toArray()); } @Test public void testFindClass() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); + + Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); + Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + + mAa.parseZip(mOsJarPath, zipClasses, filesFound); TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams", @@ -105,7 +118,11 @@ public class AsmAnalyzerTest { @Test public void testFindGlobs() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); + + Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); + Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + + mAa.parseZip(mOsJarPath, zipClasses, filesFound); TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); // this matches classes, a package match returns nothing @@ -164,7 +181,11 @@ public class AsmAnalyzerTest { @Test public void testFindClassesDerivingFrom() throws LogAbortException, IOException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); + + Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); + Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + + mAa.parseZip(mOsJarPath, zipClasses, filesFound); TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found); @@ -186,7 +207,11 @@ public class AsmAnalyzerTest { @Test public void testDependencyVisitor() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); + + Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); + Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + + mAa.parseZip(mOsJarPath, zipClasses, filesFound); TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>(); TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>(); TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>(); diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java index 8a27173..0dbc238 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java @@ -33,6 +33,7 @@ import org.objectweb.asm.Type; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; @@ -131,7 +132,8 @@ public class AsmGeneratorTest { new String[] { // include classes "**" }, - new HashSet<String>(0) /* excluded classes */); + new HashSet<String>(0) /* excluded classes */, + new String[]{} /* include files */); aa.analyze(); agen.generate(); @@ -195,10 +197,15 @@ public class AsmGeneratorTest { new String[] { // include classes "**" }, - new HashSet<String>(1)); + new HashSet<String>(1), + new String[] { /* include files */ + "mock_android/data/data*" + }); aa.analyze(); agen.generate(); - Map<String, ClassReader> output = parseZip(mOsDestJar); + Map<String, ClassReader> output = new TreeMap<String, ClassReader>(); + Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + parseZip(mOsDestJar, output, filesFound); boolean injectedClassFound = false; for (ClassReader cr: output.values()) { TestClassVisitor cv = new TestClassVisitor(); @@ -206,10 +213,13 @@ public class AsmGeneratorTest { injectedClassFound |= cv.mInjectedClassFound; } assertTrue(injectedClassFound); + assertArrayEquals(new String[] {"mock_android/data/dataFile"}, + filesFound.keySet().toArray()); } - private Map<String,ClassReader> parseZip(String jarPath) throws IOException { - TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>(); + private void parseZip(String jarPath, + Map<String, ClassReader> classes, + Map<String, InputStream> filesFound) throws IOException { ZipFile zip = new ZipFile(jarPath); Enumeration<? extends ZipEntry> entries = zip.entries(); @@ -220,10 +230,11 @@ public class AsmGeneratorTest { ClassReader cr = new ClassReader(zip.getInputStream(entry)); String className = classReaderToClassName(cr); classes.put(className, cr); + } else { + filesFound.put(entry.getName(), zip.getInputStream(entry)); } } - return classes; } private String classReaderToClassName(ClassReader classReader) { diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar Binary files differindex 60d8efb..8dd0481 100644 --- a/tools/layoutlib/create/tests/data/mock_android.jar +++ b/tools/layoutlib/create/tests/data/mock_android.jar diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile new file mode 100644 index 0000000..ab29fbe --- /dev/null +++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile @@ -0,0 +1 @@ +A simple data file that should *not* be copied to the output jar.
\ No newline at end of file diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile new file mode 100644 index 0000000..9b01893 --- /dev/null +++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile @@ -0,0 +1 @@ +A simple data file that should be copied to the output jar unchanged.
\ No newline at end of file |