summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt/AaptAssets.cpp45
-rw-r--r--tools/aapt/AaptAssets.h8
-rw-r--r--tools/aapt/Bundle.h6
-rw-r--r--tools/aapt/Command.cpp2
-rw-r--r--tools/aapt/Main.cpp2
-rw-r--r--tools/layoutlib/Android.mk5
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java124
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java63
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java40
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java3
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java15
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java6
-rw-r--r--tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java103
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java4
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java4
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java4
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java69
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java31
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java2
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java5
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java39
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java23
-rw-r--r--tools/layoutlib/create/tests/data/mock_android.jarbin9096 -> 14872 bytes
-rw-r--r--tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile1
-rw-r--r--tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile1
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
index 60d8efb..8dd0481 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
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