summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'tools/layoutlib/bridge')
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap.java4
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas.java90
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java534
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface.java48
-rw-r--r--tools/layoutlib/bridge/src/android/webkit/WebView.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java106
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java15
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java8
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java142
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java113
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java18
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java229
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java44
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java13
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/StyleResourceValue.java60
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java139
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/button.9.png (renamed from tools/layoutlib/bridge/tests/data/button.9.png)bin3750 -> 3750 bytes
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/layout1.xml (renamed from tools/layoutlib/bridge/tests/data/layout1.xml)0
19 files changed, 981 insertions, 591 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
index 7dde634..ff1b295 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
@@ -28,13 +28,13 @@ public final class Bitmap extends _Original_Bitmap {
private BufferedImage mImage;
public Bitmap(File input) throws IOException {
- super(1, true, null);
+ super(1, true, null, -1);
mImage = ImageIO.read(input);
}
Bitmap(BufferedImage image) {
- super(1, true, null);
+ super(1, true, null, -1);
mImage = image;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
index 3fa1d1d..4986c77 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
@@ -26,6 +26,7 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Xfermode;
import android.graphics.Paint.Align;
+import android.graphics.Paint.FontInfo;
import android.graphics.Paint.Style;
import android.graphics.Region.Op;
@@ -37,6 +38,7 @@ import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
+import java.util.List;
import java.util.Stack;
import javax.microedition.khronos.opengles.GL;
@@ -620,19 +622,21 @@ public class Canvas extends _Original_Canvas {
*/
@Override
public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
+ // WARNING: the logic in this method is similar to Paint.measureText.
+ // Any change to this method should be reflected in Paint.measureText
Graphics2D g = getGraphics2d();
g = (Graphics2D)g.create();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setFont(paint.getFont());
-
- // set the color. because this only handles RGB we have to handle the alpha separately
+ // set the color. because this only handles RGB, the alpha channel is handled
+ // as a composite.
g.setColor(new Color(paint.getColor()));
int alpha = paint.getAlpha();
float falpha = alpha / 255.f;
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
+
// Paint.TextAlign indicates how the text is positioned relative to X.
// LEFT is the default and there's nothing to do.
if (paint.getTextAlign() != Align.LEFT) {
@@ -644,9 +648,83 @@ public class Canvas extends _Original_Canvas {
}
}
- g.drawChars(text, index, count, (int)x, (int)y);
-
- g.dispose();
+ List<FontInfo> fonts = paint.getFonts();
+ try {
+ if (fonts.size() > 0) {
+ FontInfo mainFont = fonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // draw all the rest and exit.
+ g.setFont(mainFont.mFont);
+ g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
+ return;
+ } else if (upTo > 0) {
+ // draw what's possible
+ g.setFont(mainFont.mFont);
+ g.drawChars(text, i, upTo - i, (int)x, (int)y);
+
+ // compute the width that was drawn to increase x
+ x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+
+ // move index to the first non displayed char.
+ i = upTo;
+
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < fonts.size() ; f++) {
+ FontInfo fontInfo = fonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ // draw that char
+ g.setFont(fontInfo.mFont);
+ g.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // update x
+ x += fontInfo.mMetrics.charsWidth(text, i, charCount);
+
+ // update the index in the text, and move on
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, display it with the main font.
+ // (it'll put a square probably)
+ if (foundFont == false) {
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+
+ g.setFont(mainFont.mFont);
+ g.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // measure it to advance x
+ x += mainFont.mMetrics.charsWidth(text, i, charCount);
+
+ // and move to the next chars.
+ i += charCount;
+ }
+ }
+ }
+ } finally {
+ g.dispose();
+ }
}
/* (non-Javadoc)
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
index ade07d6..86de56b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint.java
@@ -26,6 +26,9 @@ import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* A paint implementation overridden by the LayoutLib bridge.
@@ -33,17 +36,28 @@ import java.awt.geom.Rectangle2D;
public class Paint extends _Original_Paint {
private int mColor = 0xFFFFFFFF;
+ private float mStrokeWidth = 1.f;
private float mTextSize = 20;
private float mScaleX = 1;
private float mSkewX = 0;
private Align mAlign = Align.LEFT;
private Style mStyle = Style.FILL;
+ private float mStrokeMiter = 4.0f;
+ private Cap mCap = Cap.BUTT;
+ private Join mJoin = Join.MITER;
private int mFlags = 0;
-
- private Font mFont;
+
+ /**
+ * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
+ */
+ public static final class FontInfo {
+ Font mFont;
+ java.awt.FontMetrics mMetrics;
+ }
+
+ private List<FontInfo> mFonts;
private final FontRenderContext mFontContext = new FontRenderContext(
new AffineTransform(), true, true);
- private java.awt.FontMetrics mMetrics;
@SuppressWarnings("hiding")
public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG;
@@ -65,11 +79,11 @@ public class Paint extends _Original_Paint {
public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG;
public static class FontMetrics extends _Original_Paint.FontMetrics {
- }
+ }
public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
}
-
+
/**
* The Style specifies if the primitive being drawn is filled,
* stroked, or both (in the same color). The default is FILL.
@@ -91,7 +105,7 @@ public class Paint extends _Original_Paint {
* the paint.
*/
FILL_AND_STROKE (2);
-
+
Style(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -117,7 +131,7 @@ public class Paint extends _Original_Paint {
* end of the path.
*/
SQUARE (2);
-
+
private Cap(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -141,7 +155,7 @@ public class Paint extends _Original_Paint {
* The outer edges of a join meet with a straight line
*/
BEVEL (2);
-
+
private Join(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -165,7 +179,7 @@ public class Paint extends _Original_Paint {
* The text is drawn to the left of the x,y origin
*/
RIGHT (2);
-
+
private Align(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -185,43 +199,61 @@ public class Paint extends _Original_Paint {
set(paint);
initFont();
}
-
+
@Override
public void finalize() throws Throwable {
// pass
}
-
+
+ @Override
+ public void reset() {
+ super.reset();
+ }
+
/**
- * Returns the {@link Font} object.
+ * Returns the list of {@link Font} objects. The first item is the main font, the rest
+ * are fall backs for characters not present in the main font.
*/
- public Font getFont() {
- return mFont;
+ public List<FontInfo> getFonts() {
+ return mFonts;
}
-
+
private void initFont() {
mTypeface = Typeface.DEFAULT;
updateFontObject();
}
-
+
/**
* Update the {@link Font} object from the typeface, text size and scaling
*/
+ @SuppressWarnings("deprecation")
private void updateFontObject() {
if (mTypeface != null) {
- // get the typeface font object, and get our font object from it, based on the current size
- mFont = mTypeface.getFont().deriveFont(mTextSize);
- if (mScaleX != 1.0 || mSkewX != 0) {
- // TODO: support skew
- mFont = mFont.deriveFont(new AffineTransform(
- mScaleX, mSkewX, 0, 0, 1, 0));
+ // Get the fonts from the TypeFace object.
+ List<Font> fonts = mTypeface.getFonts();
+
+ // create new font objects as well as FontMetrics, based on the current text size
+ // and skew info.
+ ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
+ for (Font font : fonts) {
+ FontInfo info = new FontInfo();
+ info.mFont = font.deriveFont(mTextSize);
+ if (mScaleX != 1.0 || mSkewX != 0) {
+ // TODO: support skew
+ info.mFont = info.mFont.deriveFont(new AffineTransform(
+ mScaleX, mSkewX, 0, 0, 1, 0));
+ }
+ info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
+
+ infoList.add(info);
}
-
- mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(mFont);
+
+ mFonts = Collections.unmodifiableList(infoList);
}
}
-
+
//----------------------------------------
-
+
public void set(Paint src) {
if (this != src) {
mColor = src.mColor;
@@ -237,6 +269,11 @@ public class Paint extends _Original_Paint {
}
@Override
+ public void setCompatibilityScaling(float factor) {
+ super.setCompatibilityScaling(factor);
+ }
+
+ @Override
public int getFlags() {
return mFlags;
}
@@ -245,7 +282,47 @@ public class Paint extends _Original_Paint {
public void setFlags(int flags) {
mFlags = flags;
}
-
+
+ @Override
+ public boolean isAntiAlias() {
+ return super.isAntiAlias();
+ }
+
+ @Override
+ public boolean isDither() {
+ return super.isDither();
+ }
+
+ @Override
+ public boolean isLinearText() {
+ return super.isLinearText();
+ }
+
+ @Override
+ public boolean isStrikeThruText() {
+ return super.isStrikeThruText();
+ }
+
+ @Override
+ public boolean isUnderlineText() {
+ return super.isUnderlineText();
+ }
+
+ @Override
+ public boolean isFakeBoldText() {
+ return super.isFakeBoldText();
+ }
+
+ @Override
+ public boolean isSubpixelText() {
+ return super.isSubpixelText();
+ }
+
+ @Override
+ public boolean isFilterBitmap() {
+ return super.isFilterBitmap();
+ }
+
/**
* Return the font's recommended interline spacing, given the Paint's
* settings for typeface, textSize, etc. If metrics is not null, return the
@@ -256,39 +333,41 @@ public class Paint extends _Original_Paint {
* @return the font's recommended interline spacing.
*/
public float getFontMetrics(FontMetrics metrics) {
- if (mMetrics != null) {
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
if (metrics != null) {
- // ascent stuff should be negatif, but awt returns them as positive.
- metrics.top = - mMetrics.getMaxAscent();
- metrics.ascent = - mMetrics.getAscent();
- metrics.descent = mMetrics.getDescent();
- metrics.bottom = mMetrics.getMaxDescent();
- metrics.leading = mMetrics.getLeading();
+ // Android expects negative ascent so we invert the value from Java.
+ metrics.top = - javaMetrics.getMaxAscent();
+ metrics.ascent = - javaMetrics.getAscent();
+ metrics.descent = javaMetrics.getDescent();
+ metrics.bottom = javaMetrics.getMaxDescent();
+ metrics.leading = javaMetrics.getLeading();
}
-
- return mMetrics.getHeight();
+
+ return javaMetrics.getHeight();
}
-
+
return 0;
}
public int getFontMetricsInt(FontMetricsInt metrics) {
- if (mMetrics != null) {
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
if (metrics != null) {
- // ascent stuff should be negatif, but awt returns them as positive.
- metrics.top = - mMetrics.getMaxAscent();
- metrics.ascent = - mMetrics.getAscent();
- metrics.descent = mMetrics.getDescent();
- metrics.bottom = mMetrics.getMaxDescent();
- metrics.leading = mMetrics.getLeading();
+ // Android expects negative ascent so we invert the value from Java.
+ metrics.top = - javaMetrics.getMaxAscent();
+ metrics.ascent = - javaMetrics.getAscent();
+ metrics.descent = javaMetrics.getDescent();
+ metrics.bottom = javaMetrics.getMaxDescent();
+ metrics.leading = javaMetrics.getLeading();
}
-
- return mMetrics.getHeight();
+
+ return javaMetrics.getHeight();
}
-
+
return 0;
}
-
+
/**
* Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
*/
@@ -297,7 +376,7 @@ public class Paint extends _Original_Paint {
getFontMetrics(fm);
return fm;
}
-
+
/**
* Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
*/
@@ -311,16 +390,14 @@ public class Paint extends _Original_Paint {
@Override
public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
@Override
public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
-
+
@Override
public Typeface setTypeface(Typeface typeface) {
if (typeface != null) {
@@ -328,12 +405,17 @@ public class Paint extends _Original_Paint {
} else {
mTypeface = Typeface.DEFAULT;
}
-
+
updateFontObject();
return typeface;
}
-
+
+ @Override
+ public Typeface getTypeface() {
+ return super.getTypeface();
+ }
+
@Override
public int getColor() {
return mColor;
@@ -344,17 +426,21 @@ public class Paint extends _Original_Paint {
mColor = color;
}
+ @Override
+ public void setARGB(int a, int r, int g, int b) {
+ super.setARGB(a, r, g, b);
+ }
@Override
public void setAlpha(int alpha) {
mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
}
-
+
@Override
public int getAlpha() {
return mColor >>> 24;
}
-
+
/**
* Set or clear the shader object.
* <p />
@@ -369,6 +455,11 @@ public class Paint extends _Original_Paint {
return mShader = shader;
}
+ @Override
+ public Shader getShader() {
+ return super.getShader();
+ }
+
/**
* Set or clear the paint's colorfilter, returning the parameter.
*
@@ -377,13 +468,15 @@ public class Paint extends _Original_Paint {
*/
@Override
public ColorFilter setColorFilter(ColorFilter filter) {
- int filterNative = 0;
- if (filter != null)
- filterNative = filter.native_instance;
mColorFilter = filter;
return filter;
}
+ @Override
+ public ColorFilter getColorFilter() {
+ return super.getColorFilter();
+ }
+
/**
* Set or clear the xfermode object.
* <p />
@@ -397,50 +490,172 @@ public class Paint extends _Original_Paint {
public Xfermode setXfermode(Xfermode xfermode) {
return mXfermode = xfermode;
}
-
+
+ @Override
+ public Xfermode getXfermode() {
+ return super.getXfermode();
+ }
+
+ @Override
+ public Rasterizer setRasterizer(Rasterizer rasterizer) {
+ mRasterizer = rasterizer;
+ return rasterizer;
+ }
+
+ @Override
+ public Rasterizer getRasterizer() {
+ return super.getRasterizer();
+ }
+
+ @Override
+ public void setShadowLayer(float radius, float dx, float dy, int color) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void clearShadowLayer() {
+ super.clearShadowLayer();
+ }
+
public void setTextAlign(Align align) {
mAlign = align;
}
-
+
@Override
public void setTextAlign(android.graphics._Original_Paint.Align align) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
-
+
public Align getTextAlign() {
return mAlign;
}
-
+
public void setStyle(Style style) {
mStyle = style;
}
@Override
public void setStyle(android.graphics._Original_Paint.Style style) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
public Style getStyle() {
return mStyle;
}
-
+
@Override
public void setDither(boolean dither) {
mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
}
-
+
@Override
public void setAntiAlias(boolean aa) {
mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
}
-
+
@Override
public void setFakeBoldText(boolean flag) {
mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
}
+ @Override
+ public void setLinearText(boolean flag) {
+ mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
+ }
+
+ @Override
+ public void setSubpixelText(boolean flag) {
+ mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
+ }
+
+ @Override
+ public void setUnderlineText(boolean flag) {
+ mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
+ }
+
+ @Override
+ public void setStrikeThruText(boolean flag) {
+ mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
+ }
+
+ @Override
+ public void setFilterBitmap(boolean flag) {
+ mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
+ }
+
+ @Override
+ public float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ @Override
+ public void setStrokeWidth(float width) {
+ mStrokeWidth = width;
+ }
+
+ @Override
+ public float getStrokeMiter() {
+ return mStrokeMiter;
+ }
+
+ @Override
+ public void setStrokeMiter(float miter) {
+ mStrokeMiter = miter;
+ }
+
+ @Override
+ public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
+ throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
+ }
+
+ public void setStrokeCap(Cap cap) {
+ mCap = cap;
+ }
+
+ public Cap getStrokeCap() {
+ return mCap;
+ }
+
+ @Override
+ public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
+ throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
+ }
+
+ public void setStrokeJoin(Join join) {
+ mJoin = join;
+ }
+
+ public Join getStrokeJoin() {
+ return mJoin;
+ }
+
+ @Override
+ public boolean getFillPath(Path src, Path dst) {
+ return super.getFillPath(src, dst);
+ }
+
+ @Override
+ public PathEffect setPathEffect(PathEffect effect) {
+ mPathEffect = effect;
+ return effect;
+ }
+
+ @Override
+ public PathEffect getPathEffect() {
+ return super.getPathEffect();
+ }
+
+ @Override
+ public MaskFilter setMaskFilter(MaskFilter maskfilter) {
+ mMaskFilter = maskfilter;
+ return maskfilter;
+ }
+
+ @Override
+ public MaskFilter getMaskFilter() {
+ return super.getMaskFilter();
+ }
+
/**
* Return the paint's text size.
*
@@ -459,7 +674,7 @@ public class Paint extends _Original_Paint {
@Override
public void setTextSize(float textSize) {
mTextSize = textSize;
-
+
updateFontObject();
}
@@ -484,7 +699,7 @@ public class Paint extends _Original_Paint {
@Override
public void setTextScaleX(float scaleX) {
mScaleX = scaleX;
-
+
updateFontObject();
}
@@ -508,10 +723,15 @@ public class Paint extends _Original_Paint {
@Override
public void setTextSkewX(float skewX) {
mSkewX = skewX;
-
+
updateFontObject();
}
+ @Override
+ public float getFontSpacing() {
+ return super.getFontSpacing();
+ }
+
/**
* Return the distance above (negative) the baseline (ascent) based on the
* current typeface and text size.
@@ -521,11 +741,12 @@ public class Paint extends _Original_Paint {
*/
@Override
public float ascent() {
- if (mMetrics != null) {
- // ascent stuff should be negatif, but awt returns them as positive.
- return - mMetrics.getAscent();
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
+ // Android expects negative ascent so we invert the value from Java.
+ return - javaMetrics.getAscent();
}
-
+
return 0;
}
@@ -538,13 +759,14 @@ public class Paint extends _Original_Paint {
*/
@Override
public float descent() {
- if (mMetrics != null) {
- return mMetrics.getDescent();
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
+ return javaMetrics.getDescent();
}
-
+
return 0;
}
-
+
/**
* Return the width of the text.
*
@@ -555,12 +777,57 @@ public class Paint extends _Original_Paint {
*/
@Override
public float measureText(char[] text, int index, int count) {
- if (mFont != null && text != null && text.length > 0) {
- Rectangle2D bounds = mFont.getStringBounds(text, index, index + count, mFontContext);
-
- return (float)bounds.getWidth();
+ // WARNING: the logic in this method is similar to Canvas.drawText.
+ // Any change to this method should be reflected in Canvas.drawText
+ if (mFonts.size() > 0) {
+ FontInfo mainFont = mFonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ float total = 0f;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // shortcut to exit
+ return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
+ } else if (upTo > 0) {
+ total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+ i = upTo;
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < mFonts.size() ; f++) {
+ FontInfo fontInfo = mFonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ total += fontInfo.mMetrics.charsWidth(text, i, charCount);
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, measure it with the main font.
+ if (foundFont == false) {
+ int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ total += mainFont.mMetrics.charsWidth(text, i, size);
+ i += size;
+ }
+ }
}
-
+
return 0;
}
@@ -587,7 +854,7 @@ public class Paint extends _Original_Paint {
public float measureText(String text) {
return measureText(text.toCharArray(), 0, text.length());
}
-
+
/*
* re-implement to call SpannableStringBuilder.measureText with a Paint object
* instead of an _Original_Paint
@@ -611,7 +878,7 @@ public class Paint extends _Original_Paint {
TemporaryBuffer.recycle(buf);
return result;
}
-
+
/**
* Measure the text, stopping early if the measured width exceeds maxWidth.
* Return the number of chars that were measured, and if measuredWidth is
@@ -633,7 +900,7 @@ public class Paint extends _Original_Paint {
public int breakText(char[] text, int index, int count,
float maxWidth, float[] measuredWidth) {
int inc = count > 0 ? 1 : -1;
-
+
int measureIndex = 0;
float measureAcc = 0;
for (int i = index ; i != index + count ; i += inc, measureIndex++) {
@@ -645,23 +912,23 @@ public class Paint extends _Original_Paint {
start = index;
end = i;
}
-
+
// measure from start to end
float res = measureText(text, start, end - start + 1);
-
+
if (measuredWidth != null) {
measuredWidth[measureIndex] = res;
}
-
+
measureAcc += res;
if (res > maxWidth) {
// we should not return this char index, but since it's 0-based and we need
// to return a count, we simply return measureIndex;
return measureIndex;
}
-
+
}
-
+
return measureIndex;
}
@@ -690,6 +957,28 @@ public class Paint extends _Original_Paint {
}
/**
+ * Measure the text, stopping early if the measured width exceeds maxWidth.
+ * Return the number of chars that were measured, and if measuredWidth is
+ * not null, return in it the actual width measured.
+ *
+ * @param text The text to measure
+ * @param start The offset into text to begin measuring at
+ * @param end The end of the text slice to measure.
+ * @param measureForwards If true, measure forwards, starting at start.
+ * Otherwise, measure backwards, starting with end.
+ * @param maxWidth The maximum width to accumulate.
+ * @param measuredWidth Optional. If not null, returns the actual width
+ * measured.
+ * @return The number of chars that were measured. Will always be <=
+ * abs(end - start).
+ */
+ @Override
+ public int breakText(CharSequence text, int start, int end, boolean measureForwards,
+ float maxWidth, float[] measuredWidth) {
+ return super.breakText(text, start, end, measureForwards, maxWidth, measuredWidth);
+ }
+
+ /**
* Return the advance widths for the characters in the string.
*
* @param text The text to measure
@@ -702,19 +991,35 @@ public class Paint extends _Original_Paint {
@Override
public int getTextWidths(char[] text, int index, int count,
float[] widths) {
- if (mMetrics != null) {
+ if (mFonts.size() > 0) {
if ((index | count) < 0 || index + count > text.length
|| count > widths.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
+ // FIXME: handle multi-char characters.
+ // Need to figure out if the lengths of the width array takes into account
+ // multi-char characters.
for (int i = 0; i < count; i++) {
- widths[i] = mMetrics.charWidth(text[i + index]);
+ char c = text[i + index];
+ boolean found = false;
+ for (FontInfo info : mFonts) {
+ if (info.mFont.canDisplay(c)) {
+ widths[i] = info.mMetrics.charWidth(c);
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ // we stop there.
+ return i;
+ }
}
-
+
return count;
}
-
+
return 0;
}
@@ -736,10 +1041,10 @@ public class Paint extends _Original_Paint {
if (end - start > widths.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
return getTextWidths(text.toCharArray(), start, end - start, widths);
}
-
+
/*
* re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
* instead of an _Original_Paint
@@ -763,6 +1068,10 @@ public class Paint extends _Original_Paint {
return result;
}
+ @Override
+ public int getTextWidths(String text, float[] widths) {
+ return super.getTextWidths(text, widths);
+ }
/**
* Return the path (outline) for the specified text.
@@ -782,13 +1091,13 @@ public class Paint extends _Original_Paint {
float x, float y, Path path) {
// TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
-
+
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
// TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
-
+
throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
}
@@ -811,10 +1120,10 @@ public class Paint extends _Original_Paint {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
-
+
getTextPath(text.toCharArray(), start, end - start, x, y, path);
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -833,10 +1142,10 @@ public class Paint extends _Original_Paint {
if (bounds == null) {
throw new NullPointerException("need bounds Rect");
}
-
+
getTextBounds(text.toCharArray(), start, end - start, bounds);
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -849,16 +1158,23 @@ public class Paint extends _Original_Paint {
*/
@Override
public void getTextBounds(char[] text, int index, int count, Rect bounds) {
- if (mFont != null) {
+ // FIXME
+ if (mFonts.size() > 0) {
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
if (bounds == null) {
throw new NullPointerException("need bounds Rect");
}
-
- Rectangle2D rect = mFont.getStringBounds(text, index, index + count, mFontContext);
+
+ FontInfo mainInfo = mFonts.get(0);
+
+ Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
}
}
+
+ public static void finalizer(int foo) {
+ // pass
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface.java b/tools/layoutlib/bridge/src/android/graphics/Typeface.java
index e878b04..af3adb5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface.java
@@ -21,9 +21,12 @@ import com.android.layoutlib.bridge.FontLoader;
import android.content.res.AssetManager;
import java.awt.Font;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
- * Re-implementation of Typeface over java.awt
+ * Re-implementation of Typeface over java.awt
*/
public class Typeface {
private static final String DEFAULT_FAMILY = "sans-serif";
@@ -46,11 +49,11 @@ public class Typeface {
private static Typeface[] sDefaults;
private static FontLoader mFontLoader;
-
+
private final int mStyle;
- private final Font mFont;
+ private final List<Font> mFonts;
private final String mFamily;
-
+
// Style
public static final int NORMAL = _Original_Typeface.NORMAL;
public static final int BOLD = _Original_Typeface.BOLD;
@@ -58,12 +61,13 @@ public class Typeface {
public static final int BOLD_ITALIC = _Original_Typeface.BOLD_ITALIC;
/**
- * Returns the underlying {@link Font} object.
+ * Returns the underlying {@link Font} objects. The first item in the list is the real
+ * font. Any other items are fallback fonts for characters not found in the first one.
*/
- public Font getFont() {
- return mFont;
+ public List<Font> getFonts() {
+ return mFonts;
}
-
+
/** Returns the typeface's intrinsic style attributes */
public int getStyle() {
return mStyle;
@@ -94,9 +98,12 @@ public class Typeface {
styleBuffer[0] = style;
Font font = mFontLoader.getFont(familyName, styleBuffer);
if (font != null) {
- return new Typeface(familyName, styleBuffer[0], font);
+ ArrayList<Font> list = new ArrayList<Font>();
+ list.add(font);
+ list.addAll(mFontLoader.getFallBackFonts());
+ return new Typeface(familyName, styleBuffer[0], list);
}
-
+
return null;
}
@@ -115,7 +122,10 @@ public class Typeface {
styleBuffer[0] = style;
Font font = mFontLoader.getFont(family.mFamily, styleBuffer);
if (font != null) {
- return new Typeface(family.mFamily, styleBuffer[0], font);
+ ArrayList<Font> list = new ArrayList<Font>();
+ list.add(font);
+ list.addAll(mFontLoader.getFallBackFonts());
+ return new Typeface(family.mFamily, styleBuffer[0], list);
}
return null;
@@ -129,7 +139,7 @@ public class Typeface {
public static Typeface defaultFromStyle(int style) {
return sDefaults[style];
}
-
+
/**
* Create a new typeface from the specified font data.
* @param mgr The application's asset manager
@@ -140,17 +150,17 @@ public class Typeface {
return null;
//return new Typeface(nativeCreateFromAsset(mgr, path));
}
-
+
// don't allow clients to call this directly
- private Typeface(String family, int style, Font f) {
+ private Typeface(String family, int style, List<Font> fonts) {
mFamily = family;
- mFont = f;
+ mFonts = Collections.unmodifiableList(fonts);
mStyle = style;
}
-
+
public static void init(FontLoader fontLoader) {
mFontLoader = fontLoader;
-
+
DEFAULT = create(DEFAULT_FAMILY, NORMAL);
DEFAULT_BOLD = create(DEFAULT_FAMILY, BOLD);
SANS_SERIF = create("sans-serif", NORMAL);
@@ -162,14 +172,14 @@ public class Typeface {
create(DEFAULT_FAMILY, ITALIC),
create(DEFAULT_FAMILY, BOLD_ITALIC),
};
-
+
/*
DEFAULT = create((String)null, 0);
DEFAULT_BOLD = create((String)null, Typeface.BOLD);
SANS_SERIF = create("sans-serif", 0);
SERIF = create("serif", 0);
MONOSPACE = create("monospace", 0);
-
+
sDefaults = new Typeface[] {
DEFAULT,
DEFAULT_BOLD,
diff --git a/tools/layoutlib/bridge/src/android/webkit/WebView.java b/tools/layoutlib/bridge/src/android/webkit/WebView.java
index 42e4dfa..3b66188 100644
--- a/tools/layoutlib/bridge/src/android/webkit/WebView.java
+++ b/tools/layoutlib/bridge/src/android/webkit/WebView.java
@@ -240,13 +240,6 @@ public class WebView extends MockView {
return null;
}
- public static synchronized PluginList getPluginList() {
- return null;
- }
-
- public void refreshPlugins(boolean reloadOpenPages) {
- }
-
public View getZoomControls() {
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 145a045..c455977 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -36,6 +36,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -312,6 +313,7 @@ public final class Bridge implements ILayoutBridge {
}
/*
+ * For compatilibty purposes, we implement the old deprecated version of computeLayout.
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
@@ -321,6 +323,23 @@ public final class Bridge implements ILayoutBridge {
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
IProjectCallback customViewLoader, ILayoutLog logger) {
+ return computeLayout(layoutDescription, projectKey,
+ screenWidth, screenHeight, false /* renderFullSize */,
+ density, xdpi, ydpi, themeName, isProjectTheme,
+ projectResources, frameworkResources, customViewLoader, logger);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, boolean, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ */
+ public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
+ int screenWidth, int screenHeight, boolean renderFullSize,
+ int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
if (logger == null) {
logger = sDefaultLogger;
}
@@ -341,6 +360,7 @@ public final class Bridge implements ILayoutBridge {
try {
// setup the display Metrics.
DisplayMetrics metrics = new DisplayMetrics();
+ metrics.densityDpi = density;
metrics.density = density / (float) DisplayMetrics.DENSITY_DEFAULT;
metrics.scaledDensity = metrics.density;
metrics.widthPixels = screenWidth;
@@ -388,20 +408,44 @@ public final class Bridge implements ILayoutBridge {
// get the background drawable
if (windowBackground != null) {
- Drawable d = ResourceHelper.getDrawable(windowBackground.getValue(),
+ Drawable d = ResourceHelper.getDrawable(windowBackground,
context, true /* isFramework */);
root.setBackgroundDrawable(d);
}
- int w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
- int h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
- MeasureSpec.EXACTLY);
-
// measure the views
+ int w_spec, h_spec;
+
+ if (renderFullSize) {
+ // measure the full size needed by the layout.
+ w_spec = MeasureSpec.makeMeasureSpec(screenWidth,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ view.measure(w_spec, h_spec);
+
+ int neededWidth = root.getChildAt(0).getMeasuredWidth();
+ if (neededWidth > screenWidth) {
+ screenWidth = neededWidth;
+ }
+
+ int neededHeight = root.getChildAt(0).getMeasuredHeight();
+ if (neededHeight > screenHeight - screenOffset) {
+ screenHeight = neededHeight + screenOffset;
+ }
+ }
+
+ // remeasure with only the size we need
+ // This must always be done before the call to layout
+ w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
+ h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
+ MeasureSpec.EXACTLY);
view.measure(w_spec, h_spec);
+
+ // now do the layout.
view.layout(0, screenOffset, screenWidth, screenHeight);
- // draw them
+ // draw the views
Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger);
root.draw(canvas);
@@ -1009,11 +1053,40 @@ public final class Bridge implements ILayoutBridge {
// pass for now.
}
+ @SuppressWarnings("unused")
public void setInsets(IWindow window, int touchable, Rect contentInsets,
Rect visibleInsets) {
// pass for now.
}
+ @SuppressWarnings("unused")
+ public void setWallpaperPosition(IBinder window, float x, float y,
+ float xStep, float yStep) {
+ // pass for now.
+ }
+
+ @SuppressWarnings("unused")
+ public void wallpaperOffsetsComplete(IBinder window) {
+ // pass for now.
+ }
+
+ @SuppressWarnings("unused")
+ public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
+ int z, Bundle extras, boolean sync) {
+ // pass for now.
+ return null;
+ }
+
+ @SuppressWarnings("unused")
+ public void wallpaperCommandComplete(IBinder window, Bundle result) {
+ // pass for now.
+ }
+
+ @SuppressWarnings("unused")
+ public void closeSystemDialogs(String reason) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
@@ -1041,12 +1114,12 @@ public final class Bridge implements ILayoutBridge {
}
@SuppressWarnings("unused")
- public void dispatchPointer(MotionEvent arg0, long arg1) throws RemoteException {
+ public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
// pass for now.
}
@SuppressWarnings("unused")
- public void dispatchTrackball(MotionEvent arg0, long arg1) throws RemoteException {
+ public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
// pass for now.
}
@@ -1067,6 +1140,23 @@ public final class Bridge implements ILayoutBridge {
// pass for now.
}
+ @SuppressWarnings("unused")
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
+ boolean sync) {
+ // pass for now.
+ }
+
+ @SuppressWarnings("unused")
+ public void dispatchWallpaperCommand(String action, int x, int y,
+ int z, Bundle extras, boolean sync) {
+ // pass for now.
+ }
+
+ @SuppressWarnings("unused")
+ public void closeSystemDialogs(String reason) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index f48c8db..1e9f573 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -27,6 +27,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
@@ -1098,6 +1099,13 @@ public final class BridgeContext extends Context {
}
@Override
+ public void sendStickyOrderedBroadcast(Intent intent,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
+ Bundle initialExtras) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void setTheme(int arg0) {
// TODO Auto-generated method stub
@@ -1124,6 +1132,13 @@ public final class BridgeContext extends Context {
}
@Override
+ public void startIntentSender(IntentSender intent,
+ Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+ throws IntentSender.SendIntentException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public boolean startInstrumentation(ComponentName arg0, String arg1,
Bundle arg2) {
// TODO Auto-generated method stub
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
index 2b0100b..1fafef4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
@@ -124,7 +124,7 @@ public final class BridgeResources extends Resources {
IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
- return ResourceHelper.getDrawable(value.getValue(), mContext, value.isFramework());
+ return ResourceHelper.getDrawable(value, mContext, value.isFramework());
}
// id was not found or not resolved. Throw a NotFoundException.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
index 10421de..957f737 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
@@ -659,8 +659,9 @@ public final class BridgeTypedArray extends TypedArray {
return null;
}
- String value = mData[index].getValue();
- if (value == null || BridgeConstants.REFERENCE_NULL.equals(value)) {
+ IResourceValue value = mData[index];
+ String stringValue = value.getValue();
+ if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) {
return null;
}
@@ -672,7 +673,8 @@ public final class BridgeTypedArray extends TypedArray {
// looks like we were unable to resolve the drawable
mContext.getLogger().warning(String.format(
- "Unable to resolve drawable \"%1$s\" in attribute \"%2$s\"", value, mNames[index]));
+ "Unable to resolve drawable \"%1$s\" in attribute \"%2$s\"", stringValue,
+ mNames[index]));
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java
index 1bdd1cc..801503b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java
@@ -29,6 +29,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -47,14 +48,13 @@ import javax.xml.parsers.SAXParserFactory;
*/
public final class FontLoader {
private static final String FONTS_DEFINITIONS = "fonts.xml";
-
+
private static final String NODE_FONTS = "fonts";
private static final String NODE_FONT = "font";
private static final String NODE_NAME = "name";
-
- private static final String ATTR_TTF = "ttf";
+ private static final String NODE_FALLBACK = "fallback";
- private static final String[] NODE_LEVEL = { NODE_FONTS, NODE_FONT, NODE_NAME };
+ private static final String ATTR_TTF = "ttf";
private static final String FONT_EXT = ".ttf";
@@ -62,7 +62,7 @@ public final class FontLoader {
private static final String[] FONT_STYLE_BOLD = { "-Bold" };
private static final String[] FONT_STYLE_ITALIC = { "-Italic" };
private static final String[] FONT_STYLE_BOLDITALIC = { "-BoldItalic" };
-
+
// list of font style, in the order matching the Typeface Font style
private static final String[][] FONT_STYLES = {
FONT_STYLE_DEFAULT,
@@ -70,23 +70,25 @@ public final class FontLoader {
FONT_STYLE_ITALIC,
FONT_STYLE_BOLDITALIC
};
-
+
private final Map<String, String> mFamilyToTtf = new HashMap<String, String>();
private final Map<String, Map<Integer, Font>> mTtfToFontMap =
new HashMap<String, Map<Integer, Font>>();
-
+
+ private List<Font> mFallBackFonts = null;
+
public static FontLoader create(String fontOsLocation) {
try {
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);
-
+
SAXParser parser = parserFactory.newSAXParser();
File f = new File(fontOsLocation + File.separator + FONTS_DEFINITIONS);
-
+
FontDefinitionParser definitionParser = new FontDefinitionParser(
fontOsLocation + File.separator);
parser.parse(new FileInputStream(f), definitionParser);
-
+
return definitionParser.getFontLoader();
} catch (ParserConfigurationException e) {
// return null below
@@ -101,12 +103,35 @@ public final class FontLoader {
return null;
}
- private FontLoader(List<FontInfo> fontList) {
+ private FontLoader(List<FontInfo> fontList, List<String> fallBackList) {
for (FontInfo info : fontList) {
for (String family : info.families) {
mFamilyToTtf.put(family, info.ttf);
}
}
+
+ ArrayList<Font> list = new ArrayList<Font>();
+ for (String path : fallBackList) {
+ File f = new File(path + FONT_EXT);
+ if (f.isFile()) {
+ try {
+ Font font = Font.createFont(Font.TRUETYPE_FONT, f);
+ if (font != null) {
+ list.add(font);
+ }
+ } catch (FontFormatException e) {
+ // skip this font name
+ } catch (IOException e) {
+ // skip this font name
+ }
+ }
+ }
+
+ mFallBackFonts = Collections.unmodifiableList(list);
+ }
+
+ public List<Font> getFallBackFonts() {
+ return mFallBackFonts;
}
public synchronized Font getFont(String family, int[] style) {
@@ -116,25 +141,25 @@ public final class FontLoader {
// get the ttf name from the family
String ttf = mFamilyToTtf.get(family);
-
+
if (ttf == null) {
return null;
}
-
+
// get the font from the ttf
Map<Integer, Font> styleMap = mTtfToFontMap.get(ttf);
-
+
if (styleMap == null) {
styleMap = new HashMap<Integer, Font>();
mTtfToFontMap.put(ttf, styleMap);
}
-
+
Font f = styleMap.get(style);
-
+
if (f != null) {
return f;
}
-
+
// if it doesn't exist, we create it, and we can't, we try with a simpler style
switch (style[0]) {
case Typeface.NORMAL:
@@ -178,7 +203,7 @@ public final class FontLoader {
private Font getFont(String ttf, String[] fontFileSuffix) {
for (String suffix : fontFileSuffix) {
String name = ttf + suffix + FONT_EXT;
-
+
File f = new File(name);
if (f.isFile()) {
try {
@@ -193,14 +218,14 @@ public final class FontLoader {
}
}
}
-
+
return null;
}
private final static class FontInfo {
String ttf;
final Set<String> families;
-
+
FontInfo() {
families = new HashSet<String>();
}
@@ -208,19 +233,19 @@ public final class FontLoader {
private final static class FontDefinitionParser extends DefaultHandler {
private final String mOsFontsLocation;
-
- private int mDepth = 0;
+
private FontInfo mFontInfo = null;
private final StringBuilder mBuilder = new StringBuilder();
- private final List<FontInfo> mFontList = new ArrayList<FontInfo>();
-
+ private List<FontInfo> mFontList;
+ private List<String> mFallBackList;
+
private FontDefinitionParser(String osFontsLocation) {
super();
mOsFontsLocation = osFontsLocation;
}
-
+
FontLoader getFontLoader() {
- return new FontLoader(mFontList);
+ return new FontLoader(mFontList, mFallBackList);
}
/* (non-Javadoc)
@@ -229,10 +254,11 @@ public final class FontLoader {
@Override
public void startElement(String uri, String localName, String name, Attributes attributes)
throws SAXException {
- if (localName.equals(NODE_LEVEL[mDepth])) {
- mDepth++;
-
- if (mDepth == 2) { // font level.
+ if (NODE_FONTS.equals(localName)) {
+ mFontList = new ArrayList<FontInfo>();
+ mFallBackList = new ArrayList<String>();
+ } else if (NODE_FONT.equals(localName)) {
+ if (mFontList != null) {
String ttf = attributes.getValue(ATTR_TTF);
if (ttf != null) {
mFontInfo = new FontInfo();
@@ -240,42 +266,50 @@ public final class FontLoader {
mFontList.add(mFontInfo);
}
}
+ } else if (NODE_NAME.equals(localName)) {
+ // do nothing, we'll handle the name in the endElement
+ } else if (NODE_FALLBACK.equals(localName)) {
+ if (mFallBackList != null) {
+ String ttf = attributes.getValue(ATTR_TTF);
+ if (ttf != null) {
+ mFallBackList.add(mOsFontsLocation + ttf);
+ }
+ }
}
+ mBuilder.setLength(0);
+
super.startElement(uri, localName, name, attributes);
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
- @SuppressWarnings("unused")
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
- if (mFontInfo != null) {
- mBuilder.append(ch, start, length);
- }
+ mBuilder.append(ch, start, length);
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
*/
- @SuppressWarnings("unused")
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
- if (localName.equals(NODE_LEVEL[mDepth-1])) {
- mDepth--;
- if (mDepth == 2) { // end of a <name> node
- if (mFontInfo != null) {
- String family = trimXmlWhitespaces(mBuilder.toString());
- mFontInfo.families.add(family);
- mBuilder.setLength(0);
- }
- } else if (mDepth == 1) { // end of a <font> node
- mFontInfo = null;
+ if (NODE_FONTS.equals(localName)) {
+ // top level, do nothing
+ } else if (NODE_FONT.equals(localName)) {
+ mFontInfo = null;
+ } else if (NODE_NAME.equals(localName)) {
+ // handle a new name for an existing Font Info
+ if (mFontInfo != null) {
+ String family = trimXmlWhitespaces(mBuilder.toString());
+ mFontInfo.families.add(family);
}
+ } else if (NODE_FALLBACK.equals(localName)) {
+ // nothing to do here.
}
}
-
+
private String trimXmlWhitespaces(String value) {
if (value == null) {
return null;
@@ -283,7 +317,7 @@ public final class FontLoader {
// look for carriage return and replace all whitespace around it by just 1 space.
int index;
-
+
while ((index = value.indexOf('\n')) != -1) {
// look for whitespace on each side
int left = index - 1;
@@ -294,7 +328,7 @@ public final class FontLoader {
break;
}
}
-
+
int right = index + 1;
int count = value.length();
while (right < count) {
@@ -304,7 +338,7 @@ public final class FontLoader {
break;
}
}
-
+
// remove all between left and right (non inclusive) and replace by a single space.
String leftString = null;
if (left >= 0) {
@@ -314,7 +348,7 @@ public final class FontLoader {
if (right < count) {
rightString = value.substring(right);
}
-
+
if (leftString != null) {
value = leftString;
if (rightString != null) {
@@ -324,24 +358,24 @@ public final class FontLoader {
value = rightString != null ? rightString : "";
}
}
-
+
// now we un-escape the string
int length = value.length();
char[] buffer = value.toCharArray();
-
+
for (int i = 0 ; i < length ; i++) {
if (buffer[i] == '\\') {
if (buffer[i+1] == 'n') {
// replace the char with \n
buffer[i+1] = '\n';
}
-
+
// offset the rest of the buffer since we go from 2 to 1 char
System.arraycopy(buffer, i+1, buffer, i, length - i - 1);
length--;
}
}
-
+
return new String(buffer, 0, length);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
index fbdf8dc..3d0dd73 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
@@ -16,6 +16,9 @@
package com.android.layoutlib.bridge;
+import com.android.layoutlib.api.IDensityBasedResourceValue;
+import com.android.layoutlib.api.IResourceValue;
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
import com.android.ninepatch.NinePatch;
import org.kxml2.io.KXmlParser;
@@ -40,7 +43,7 @@ import java.util.regex.Pattern;
* Helper class to provide various convertion method used in handling android resources.
*/
public final class ResourceHelper {
-
+
private final static Pattern sFloatPattern = Pattern.compile("(-?[0-9]+(?:\\.[0-9]+)?)(.*)");
private final static float[] sFloatOut = new float[1];
@@ -59,12 +62,12 @@ public final class ResourceHelper {
}
value = value.substring(1);
-
+
// make sure it's not longer than 32bit
if (value.length() > 8) {
throw new NumberFormatException();
}
-
+
if (value.length() == 3) { // RGB format
char[] color = new char[8];
color[0] = color[1] = 'F';
@@ -84,7 +87,7 @@ public final class ResourceHelper {
}
// this is a RRGGBB or AARRGGBB value
-
+
// Integer.parseInt will fail to parse strings like "ff191919", so we use
// a Long, but cast the result back into an int, since we know that we're only
// dealing with 32 bit values.
@@ -96,28 +99,30 @@ public final class ResourceHelper {
/**
* Returns a drawable from the given value.
- * @param value The value. A path to a 9 patch, a bitmap or a xml based drawable,
+ * @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
* or an hexadecimal color
- * @param context
+ * @param context
* @param isFramework indicates whether the resource is a framework resources.
* Framework resources are cached, and loaded only once.
*/
- public static Drawable getDrawable(String value, BridgeContext context, boolean isFramework) {
+ public static Drawable getDrawable(IResourceValue value, BridgeContext context, boolean isFramework) {
Drawable d = null;
-
- String lowerCaseValue = value.toLowerCase();
+
+ String stringValue = value.getValue();
+
+ String lowerCaseValue = stringValue.toLowerCase();
if (lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) {
- File f = new File(value);
- if (f.isFile()) {
- NinePatch ninePatch = Bridge.getCached9Patch(value,
+ File file = new File(stringValue);
+ if (file.isFile()) {
+ NinePatch ninePatch = Bridge.getCached9Patch(stringValue,
isFramework ? null : context.getProjectKey());
-
+
if (ninePatch == null) {
try {
- ninePatch = NinePatch.load(new File(value).toURL(), false /* convert */);
-
- Bridge.setCached9Patch(value, ninePatch,
+ ninePatch = NinePatch.load(file.toURL(), false /* convert */);
+
+ Bridge.setCached9Patch(stringValue, ninePatch,
isFramework ? null : context.getProjectKey());
} catch (MalformedURLException e) {
// URL is wrong, we'll return null below
@@ -125,23 +130,23 @@ public final class ResourceHelper {
// failed to read the file, we'll return null below.
}
}
-
+
if (ninePatch != null) {
return new NinePatchDrawable(ninePatch);
}
}
-
+
return null;
} else if (lowerCaseValue.endsWith(".xml")) {
// create a blockparser for the file
- File f = new File(value);
+ File f = new File(stringValue);
if (f.isFile()) {
try {
// let the framework inflate the Drawable from the XML file.
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(f));
-
+
d = Drawable.createFromXml(context.getResources(),
// FIXME: we need to know if this resource is platform or not
new BridgeXmlBlockParser(parser, context, false));
@@ -157,19 +162,43 @@ public final class ResourceHelper {
return null;
} else {
- File bmpFile = new File(value);
+ File bmpFile = new File(stringValue);
if (bmpFile.isFile()) {
try {
- Bitmap bitmap = Bridge.getCachedBitmap(value,
+ Bitmap bitmap = Bridge.getCachedBitmap(stringValue,
isFramework ? null : context.getProjectKey());
-
+
if (bitmap == null) {
bitmap = new Bitmap(bmpFile);
- Bridge.setCachedBitmap(value, bitmap,
+ try {
+ bitmap.setDensity(Density.MEDIUM.getValue());
+ } catch (NoClassDefFoundError error) {
+ // look like we're running in an older version of ADT that doesn't
+ // include the new layoutlib_api. Let's just ignore this, the drawing
+ // will just be wrong.
+ }
+ Bridge.setCachedBitmap(stringValue, bitmap,
isFramework ? null : context.getProjectKey());
}
-
- return new BitmapDrawable(bitmap);
+
+ try {
+ if (value instanceof IDensityBasedResourceValue) {
+ Density density = ((IDensityBasedResourceValue)value).getDensity();
+ if (density != Density.MEDIUM) {
+ // create a copy of the bitmap
+ bitmap = Bitmap.createBitmap(bitmap);
+
+ // apply the density
+ bitmap.setDensity(density.getValue());
+ }
+ }
+ } catch (NoClassDefFoundError error) {
+ // look like we're running in an older version of ADT that doesn't include
+ // the new layoutlib_api. Let's just ignore this, the drawing will just be
+ // wrong.
+ }
+
+ return new BitmapDrawable(context.getResources(), bitmap);
} catch (IOException e) {
// we'll return null below
// TODO: log the error.
@@ -177,7 +206,7 @@ public final class ResourceHelper {
} else {
// attempt to get a color from the value
try {
- int color = getColor(value);
+ int color = getColor(stringValue);
return new ColorDrawable(color);
} catch (NumberFormatException e) {
// we'll return null below.
@@ -185,20 +214,20 @@ public final class ResourceHelper {
}
}
}
-
+
return null;
}
-
+
// ------- TypedValue stuff
// This is taken from //device/libs/utils/ResourceTypes.cpp
-
+
private static final class UnitEntry {
String name;
int type;
int unit;
float scale;
-
+
UnitEntry(String name, int type, int unit, float scale) {
this.name = name;
this.type = type;
@@ -218,7 +247,7 @@ public final class ResourceHelper {
new UnitEntry("%", TypedValue.TYPE_FRACTION, TypedValue.COMPLEX_UNIT_FRACTION, 1.0f/100),
new UnitEntry("%p", TypedValue.TYPE_FRACTION, TypedValue.COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100),
};
-
+
/**
* Returns the raw value from the given string.
* This object is only valid until the next call on to {@link ResourceHelper}.
@@ -227,10 +256,10 @@ public final class ResourceHelper {
if (stringToFloat(s, mValue)) {
return mValue;
}
-
+
return null;
}
-
+
/**
* Convert the string into a {@link TypedValue}.
* @param s
@@ -258,7 +287,7 @@ public final class ResourceHelper {
if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
return false;
}
-
+
// now look for the string that is after the float...
Matcher m = sFloatPattern.matcher(s);
if (m.matches()) {
@@ -272,11 +301,11 @@ public final class ResourceHelper {
// this shouldn't happen with the regexp above.
return false;
}
-
+
if (end.length() > 0 && end.charAt(0) != ' ') {
// Might be a unit...
if (parseUnit(end, outValue, sFloatOut)) {
-
+
f *= sFloatOut[0];
boolean neg = f < 0;
if (neg) {
@@ -312,17 +341,17 @@ public final class ResourceHelper {
if (neg) {
mantissa = (-mantissa) & TypedValue.COMPLEX_MANTISSA_MASK;
}
- outValue.data |=
+ outValue.data |=
(radix<<TypedValue.COMPLEX_RADIX_SHIFT)
| (mantissa<<TypedValue.COMPLEX_MANTISSA_SHIFT);
return true;
}
return false;
}
-
+
// make sure it's only spaces at the end.
end = end.trim();
-
+
if (end.length() == 0) {
if (outValue != null) {
outValue.type = TypedValue.TYPE_FLOAT;
@@ -334,7 +363,7 @@ public final class ResourceHelper {
return false;
}
-
+
private static boolean parseUnit(String str, TypedValue outValue, float[] outScale) {
str = str.trim();
@@ -343,7 +372,7 @@ public final class ResourceHelper {
outValue.type = unit.type;
outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT;
outScale[0] = unit.scale;
-
+
return true;
}
}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
index ac144e7..6e14e82 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
@@ -24,7 +24,7 @@ import android.text.TextPaint;
import junit.framework.TestCase;
/**
- *
+ *
*/
public class AndroidGraphicsTests extends TestCase {
@@ -40,24 +40,24 @@ public class AndroidGraphicsTests extends TestCase {
public void testMatrix() {
Matrix m1 = new Matrix();
-
- assertFalse(m1.isIdentity());
-
+
+ assertTrue(m1.isIdentity());
+
m1.setValues(new float[] { 1,0,0, 0,1,0, 0,0,1 });
assertTrue(m1.isIdentity());
-
+
Matrix m2 = new Matrix(m1);
-
+
float[] v1 = new float[9];
float[] v2 = new float[9];
m1.getValues(v1);
m2.getValues(v2);
-
+
for (int i = 0 ; i < 9; i++) {
assertEquals(v1[i], v2[i]);
}
}
-
+
public void testPaint() {
_Original_Paint o = new _Original_Paint();
assertNotNull(o);
@@ -65,7 +65,7 @@ public class AndroidGraphicsTests extends TestCase {
Paint p = new Paint();
assertNotNull(p);
}
-
+
public void textTextPaint() {
TextPaint p = new TextPaint();
assertNotNull(p);
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java
deleted file mode 100644
index e424f1d..0000000
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeTest.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.ILayoutResult;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
-import com.android.layoutlib.api.IXmlPullParser;
-import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
-
-import org.kxml2.io.KXmlParser;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.File;
-import java.io.FileReader;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-
-import junit.framework.TestCase;
-
-public class BridgeTest extends TestCase {
-
- /** the class being tested */
- private Bridge mBridge;
- /** the path to the sample layout.xml file */
- private String mLayoutXml1Path;
- private String mTextOnlyXmlPath;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mBridge = new Bridge();
-
- // FIXME: need some fonts somewhere.
- mBridge.init(null /* fontOsLocation */, getAttributeValues());
-
- URL url = this.getClass().getClassLoader().getResource("data/layout1.xml");
- mLayoutXml1Path = url.getFile();
-
- url = this.getClass().getClassLoader().getResource("data/textonly.xml");
- mTextOnlyXmlPath = url.getFile();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- // ---------------
-
- /**
- * Test parser that implements {@link IXmlPullParser}.
- */
- private static class TestParser extends KXmlParser implements IXmlPullParser {
- public Object getViewKey() {
- return null;
- }
- }
-
- public void testComputeLayout() throws Exception {
-
- TestParser parser = new TestParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(new File(mLayoutXml1Path)));
-
- Map<String, Map<String, IResourceValue>> projectResources = getProjectResources();
-
- Map<String, Map<String, IResourceValue>> frameworkResources = getFrameworkResources();
-
- int screenWidth = 320;
- int screenHeight = 480;
-
- // FIXME need a dummy font for the tests!
- ILayoutResult result = mBridge.computeLayout(parser, new Integer(1) /* projectKey */,
- screenWidth, screenHeight,
- "Theme", projectResources, frameworkResources, null, null);
-
- display(result.getRootView(), "");
- }
-
- private Map<String, Map<String, Integer>> getAttributeValues() {
- Map<String, Map<String, Integer>> attributeValues =
- new HashMap<String, Map<String,Integer>>();
-
- // lets create a map for the orientation attribute
- Map<String, Integer> attributeMap = new HashMap<String, Integer>();
-
- attributeMap.put("horizontal", Integer.valueOf(0));
- attributeMap.put("vertical", Integer.valueOf(1));
-
- attributeValues.put("orientation", attributeMap);
-
- return attributeValues;
- }
-
- private Map<String, Map<String, IResourceValue>> getFrameworkResources() {
- Map<String, Map<String, IResourceValue>> frameworkResources =
- new HashMap<String, Map<String, IResourceValue>>();
-
- // create the style map
- Map<String, IResourceValue> styleMap = new HashMap<String, IResourceValue>();
- frameworkResources.put("style", styleMap);
-
- // create a button style.
- IStyleResourceValue style = createStyle("Widget.Button",
- "background", "@android:drawable/something",
- "focusable", "true",
- "clickable", "true",
- "textAppearance", "?android:attr/textAppearanceSmallInverse",
- "textColor", "?android:attr/textColorBrightInverseNoDisable",
- "gravity", "center_vertical|center_horizontal"
- );
- styleMap.put(style.getName(), style);
-
- // create the parent style of button style
- style = createStyle("Widget",
- "textAppearance", "?textAppearance");
- styleMap.put(style.getName(), style);
-
- // link the buttonStyle info in the default theme.
- style = createStyle("Theme",
- BridgeConstants.RES_STYLE, "buttonStyle", "@android:style/Widget.Button",
- BridgeConstants.RES_STYLE, "textAppearance", "@android:style/TextAppearance",
- BridgeConstants.RES_STYLE, "textAppearanceSmallInverse", "@android:style/TextAppearance.Small.Inverse",
- BridgeConstants.RES_COLOR, "textColorBrightInverseNoDisable", "@android:color/bright_text_light_nodisable"
- );
- styleMap.put(style.getName(), style);
-
- // create a dummy drawable to go with it
- Map<String, IResourceValue> drawableMap = new HashMap<String, IResourceValue>();
- frameworkResources.put("drawable", drawableMap);
-
- // get the 9 patch test location
- URL url = this.getClass().getClassLoader().getResource("data/button.9.png");
-
- IResourceValue drawable = new ResourceValue(BridgeConstants.RES_DRAWABLE, "something",
- url.getPath());
- drawableMap.put(drawable.getName(), drawable);
- return frameworkResources;
- }
-
- private Map<String, Map<String, IResourceValue>> getProjectResources() {
- Map<String, Map<String, IResourceValue>> projectResources =
- new HashMap<String, Map<String, IResourceValue>>();
-
- // create the style map (even empty there should be one)
- Map<String, IResourceValue> styleMap = new HashMap<String, IResourceValue>();
- projectResources.put("style", styleMap);
-
- return projectResources;
- }
-
-
- private void display(ILayoutViewInfo result, String offset) {
-
- String msg = String.format("%s%s L:%d T:%d R:%d B:%d",
- offset,
- result.getName(),
- result.getLeft(), result.getTop(), result.getRight(), result.getBottom());
-
- System.out.println(msg);
- ILayoutViewInfo[] children = result.getChildren();
- if (children != null) {
- offset += "+-";
- for (ILayoutViewInfo child : children) {
- display(child, offset);
- }
- }
- }
-
- /**
- * Creates a {@link IStyleResourceValue} based on the given values.
- * @param styleName the name of the style.
- * @param items An array of Strings. Even indices contain a style item name, and odd indices
- * a style item value. If the number of string in the array is not even, an exception is thrown.
- */
- private IStyleResourceValue createStyle(String styleName, String... items) {
- StyleResourceValue value = new StyleResourceValue(styleName);
-
- if (items.length % 3 == 0) {
- for (int i = 0 ; i < items.length;) {
- value.addItem(new ResourceValue(items[i++], items[i++], items[i++]));
- }
- } else {
- throw new IllegalArgumentException("Need a multiple of 3 for the number of strings");
- }
-
- return value;
- }
-
- // ---------------
-
- public void testTextLayout() throws Exception {
-
- TestParser parser = new TestParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(new File(mTextOnlyXmlPath)));
-
- Map<String, Map<String, IResourceValue>> projectResources = getProjectResources();
- Map<String, Map<String, IResourceValue>> frameworkResources = getFrameworkResources();
-
- int screenWidth = 320;
- int screenHeight = 480;
-
- // FIXME need a dummy font for the tests!
- ILayoutResult result = mBridge.computeLayout(parser, new Integer(1) /* projectKey */,
- screenWidth, screenHeight,
- "Theme", projectResources, frameworkResources, null, null);
-
- display(result.getRootView(), "");
- }
-
-}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
index cac1f95..db1262f 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
@@ -17,33 +17,18 @@
package com.android.layoutlib.bridge;
import org.kxml2.io.KXmlParser;
-import org.w3c.dom.Document;
import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.net.URL;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
+import java.io.InputStream;
import junit.framework.TestCase;
public class BridgeXmlBlockParserTest extends TestCase {
- private String mXmlPath;
- private Document mDoc;
-
@Override
protected void setUp() throws Exception {
super.setUp();
- URL url = this.getClass().getClassLoader().getResource("data/layout1.xml");
- mXmlPath = url.getFile();
- mDoc = getXmlDocument(mXmlPath);
}
@Override
@@ -54,7 +39,10 @@ public class BridgeXmlBlockParserTest extends TestCase {
public void testXmlBlockParser() throws Exception {
XmlPullParser parser = new KXmlParser();
parser = new BridgeXmlBlockParser(parser, null, false /* platformResourceFlag */);
- parser.setInput(new FileReader(new File(mXmlPath)));
+
+ InputStream input = this.getClass().getClassLoader().getResourceAsStream(
+ "com/android/layoutlib/testdata/layout1.xml");
+ parser.setInput(input, null /*encoding*/);
assertEquals(XmlPullParser.START_DOCUMENT, parser.next());
@@ -85,24 +73,8 @@ public class BridgeXmlBlockParserTest extends TestCase {
assertEquals(XmlPullParser.END_TAG, parser.next());
assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
}
-
- //------------
-
- private Document getXmlDocument(String xmlFilePath)
- throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-
- // keep comments
- factory.setIgnoringComments(false);
- // don't validate our bogus DTD
- factory.setValidating(false);
- // we want namespaces
- factory.setNamespaceAware(true);
-
- DocumentBuilder builder = factory.newDocumentBuilder();
- return builder.parse(new File(xmlFilePath));
- }
+ //------------
/**
* Quick'n'dirty debug helper that dumps an XML structure to stdout.
@@ -126,7 +98,7 @@ public class BridgeXmlBlockParserTest extends TestCase {
"DOCUMENT_FRAGMENT_NODE",
"NOTATION_NODE"
};
-
+
String s = String.format("%s<%s> %s %s",
prefix,
types[node.getNodeType()],
@@ -134,7 +106,7 @@ public class BridgeXmlBlockParserTest extends TestCase {
node.getNodeValue() == null ? "" : node.getNodeValue().trim());
System.out.println(s);
-
+
n = node.getFirstChild();
if (n != null) {
dump(n, prefix + "- ");
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
index 67ec5e1..d5993db 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
@@ -7,20 +7,21 @@ import java.net.URL;
import junit.framework.TestCase;
public class NinePatchTest extends TestCase {
-
+
private NinePatch mPatch;
@Override
protected void setUp() throws Exception {
- URL url = this.getClass().getClassLoader().getResource("data/button.9.png");
+ URL url = this.getClass().getClassLoader().getResource(
+ "com/android/layoutlib/testdata/button.9.png");
mPatch = NinePatch.load(url, false /* convert */);
}
-
+
public void test9PatchLoad() throws Exception {
assertNotNull(mPatch);
}
-
+
public void test9PatchMinSize() {
int[] padding = new int[4];
mPatch.getPadding(padding);
@@ -28,8 +29,8 @@ public class NinePatchTest extends TestCase {
assertEquals(3, padding[1]);
assertEquals(13, padding[2]);
assertEquals(4, padding[3]);
- assertEquals(38, mPatch.getWidth());
- assertEquals(27, mPatch.getHeight());
+ assertEquals(36, mPatch.getWidth());
+ assertEquals(25, mPatch.getHeight());
}
}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/StyleResourceValue.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/StyleResourceValue.java
deleted file mode 100644
index 84bdc2f..0000000
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/StyleResourceValue.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
-
-import java.util.HashMap;
-
-class StyleResourceValue extends ResourceValue implements IStyleResourceValue {
-
- private String mParentStyle = null;
- private HashMap<String, IResourceValue> mItems = new HashMap<String, IResourceValue>();
-
- StyleResourceValue(String name) {
- super(name);
- }
-
- StyleResourceValue(String name, String parentStyle) {
- super(name);
- mParentStyle = parentStyle;
- }
-
- public String getParentStyle() {
- return mParentStyle;
- }
-
- public IResourceValue findItem(String name) {
- return mItems.get(name);
- }
-
- public void addItem(IResourceValue value) {
- mItems.put(value.getName(), value);
- }
-
- @Override
- public void replaceWith(ResourceValue value) {
- super.replaceWith(value);
-
- if (value instanceof StyleResourceValue) {
- mItems.clear();
- mItems.putAll(((StyleResourceValue)value).mItems);
- }
- }
-
-}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java
new file mode 100644
index 0000000..e0dc55f
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge;
+
+import java.lang.reflect.Method;
+
+import junit.framework.TestCase;
+
+public class TestClassReplacement extends TestCase {
+
+ public void testClassReplacements() {
+ // TODO: we want to test all the classes. For now only Paint passes the tests.
+// final String[] classes = CreateInfo.RENAMED_CLASSES;
+ final String[] classes = new String[] {
+ "android.graphics.Paint", "android.graphics._Original_Paint"
+ };
+ final int count = classes.length;
+ for (int i = 0 ; i < count ; i += 2) {
+ loadAndCompareClasses(classes[i], classes[i+1]);
+ }
+ }
+
+ private void loadAndCompareClasses(String newClassName, String oldClassName) {
+ // load the classes
+ try {
+ Class<?> newClass = TestClassReplacement.class.getClassLoader().loadClass(newClassName);
+ Class<?> oldClass = TestClassReplacement.class.getClassLoader().loadClass(oldClassName);
+
+ compare(newClass, oldClass);
+ } catch (ClassNotFoundException e) {
+ fail("Failed to load class: " + e.getMessage());
+ }
+ }
+
+ private void compare(Class<?> newClass, Class<?> oldClass) {
+ // first compare the methods.
+ Method[] newClassMethods = newClass.getDeclaredMethods();
+ Method[] oldClassMethods = oldClass.getDeclaredMethods();
+
+ for (Method oldMethod : oldClassMethods) {
+ // we ignore anything that starts with native
+ if (oldMethod.getName().startsWith("native")) {
+ continue;
+ }
+ boolean found = false;
+ for (Method newMethod : newClassMethods) {
+ if (compareMethods(newClass, newMethod, oldClass, oldMethod)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ fail(String.format("Unable to find %1$s", oldMethod.toGenericString()));
+ }
+ }
+
+ // TODO: check (somehow?) that the methods that were removed from the original class
+ // have been put back in the new class!
+ // For this we need the original unmodified class (ie renamed, but w/o the methods removed)
+ }
+
+ private boolean compareMethods(Class<?> newClass, Method newMethod,
+ Class<?> oldClass, Method oldMethod) {
+ // first check the name of the method
+ if (newMethod.getName().equals(oldMethod.getName()) == false) {
+ return false;
+ }
+
+ // check the return value
+ Class<?> oldReturnType = oldMethod.getReturnType();
+ // if it's the old class, or if it's a inner class of the oldclass, we need to change this.
+ oldReturnType = adapt(oldReturnType, newClass, oldClass);
+
+ // compare the return types
+ Class<?> newReturnType = newMethod.getReturnType();
+ if (newReturnType.equals(oldReturnType) == false) {
+ return false;
+ }
+
+ // now check the parameters type.
+ Class<?>[] oldParameters = oldMethod.getParameterTypes();
+ Class<?>[] newParemeters = newMethod.getParameterTypes();
+ if (oldParameters.length != newParemeters.length) {
+ return false;
+ }
+
+ for (int i = 0 ; i < oldParameters.length ; i++) {
+ if (newParemeters[i].equals(adapt(oldParameters[i], newClass, oldClass)) == false) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Adapts a class to deal with renamed classes.
+ * <p/>For instance if old class is <code>android.graphics._Original_Paint</code> and the
+ * new class is <code>android.graphics.Paint</code> and the class to adapt is
+ * <code>android.graphics._Original_Paint$Cap</code>, then the method will return a
+ * {@link Class} object representing <code>android.graphics.Paint$Cap</code>.
+ * <p/>
+ * This method will also ensure that all renamed classes contains all the proper inner classes
+ * that they should be declaring.
+ * @param theClass the class to adapt
+ * @param newClass the new class object
+ * @param oldClass the old class object
+ * @return the adapted class.
+ * @throws ClassNotFoundException
+ */
+ private Class<?> adapt(Class<?> theClass, Class<?> newClass, Class<?> oldClass) {
+ // only look for a new class if it's not primitive as Class.forName() would fail otherwise.
+ if (theClass.isPrimitive() == false) {
+ String n = theClass.getName().replace(oldClass.getName(), newClass.getName());
+ try {
+ return Class.forName(n);
+ } catch (ClassNotFoundException e) {
+ fail("Missing class: " + n);
+ }
+ }
+
+ return theClass;
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/data/button.9.png b/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/button.9.png
index 9d52f40..9d52f40 100644
--- a/tools/layoutlib/bridge/tests/data/button.9.png
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/button.9.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/data/layout1.xml b/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/layout1.xml
index 554f541..554f541 100644
--- a/tools/layoutlib/bridge/tests/data/layout1.xml
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/layout1.xml