summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge/src
diff options
context:
space:
mode:
Diffstat (limited to 'tools/layoutlib/bridge/src')
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeResources.java15
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java28
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java23
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java13
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java59
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java41
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java19
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java156
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java193
-rw-r--r--tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java44
-rw-r--r--tools/layoutlib/bridge/src/android/text/LineBreaker.java43
-rw-r--r--tools/layoutlib/bridge/src/android/text/LineWidth.java35
-rw-r--r--tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java262
-rw-r--r--tools/layoutlib/bridge/src/android/text/Primitive.java92
-rw-r--r--tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java238
-rw-r--r--tools/layoutlib/bridge/src/android/text/TabStops.java44
-rw-r--r--tools/layoutlib/bridge/src/android/util/Xml_Delegate.java8
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java13
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java24
-rw-r--r--tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java106
-rw-r--r--tools/layoutlib/bridge/src/android/view/ShadowPainter.java3
-rw-r--r--tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java12
-rw-r--r--tools/layoutlib/bridge/src/android/view/View_Delegate.java13
-rw-r--r--tools/layoutlib/bridge/src/android/view/WindowCallback.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java72
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java11
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java177
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java3
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java83
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java9
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java61
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java3
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java5
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java74
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java24
43 files changed, 1614 insertions, 506 deletions
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 2c2c672..fdb6e75 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -169,7 +169,7 @@ public final class BridgeResources extends Resources {
}
@Override
- public int getColor(int id) throws NotFoundException {
+ public int getColor(int id, Theme theme) throws NotFoundException {
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
@@ -192,22 +192,21 @@ public final class BridgeResources extends Resources {
}
}
- // id was not found or not resolved. Throw a NotFoundException.
- throwException(id);
-
- // this is not used since the method above always throws
- return 0;
+ // Suppress possible NPE. getColorStateList will never return null, it will instead
+ // throw an exception, but intelliJ can't figure that out
+ //noinspection ConstantConditions
+ return getColorStateList(id, theme).getDefaultColor();
}
@Override
- public ColorStateList getColorStateList(int id) throws NotFoundException {
+ public ColorStateList getColorStateList(int id, Theme theme) throws NotFoundException {
Pair<String, ResourceValue> resValue = getResourceValue(id, mPlatformResourceFlag);
if (resValue != null) {
ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
mContext);
if (stateList != null) {
- return stateList;
+ return stateList.obtainForTheme(theme);
}
}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 7d4271b..54a508a 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -320,7 +320,8 @@ public final class BridgeTypedArray extends TypedArray {
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
parser, mContext, resValue.isFramework());
try {
- return ColorStateList.createFromXml(mContext.getResources(), blockParser);
+ return ColorStateList.createFromXml(mContext.getResources(), blockParser,
+ mContext.getTheme());
} finally {
blockParser.ensurePopped();
}
@@ -444,7 +445,7 @@ public final class BridgeTypedArray extends TypedArray {
@Override
public int getDimensionPixelSize(int index, int defValue) {
try {
- return getDimension(index);
+ return getDimension(index, null);
} catch (RuntimeException e) {
String s = getString(index);
@@ -474,12 +475,12 @@ public final class BridgeTypedArray extends TypedArray {
@Override
public int getLayoutDimension(int index, String name) {
try {
- // this will throw an exception
- return getDimension(index);
+ // this will throw an exception if not found.
+ return getDimension(index, name);
} catch (RuntimeException e) {
if (LayoutInflater_Delegate.sIsInInclude) {
- throw new RuntimeException();
+ throw new RuntimeException("Layout Dimension '" + name + "' not found.");
}
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
@@ -494,9 +495,13 @@ public final class BridgeTypedArray extends TypedArray {
return getDimensionPixelSize(index, defValue);
}
- private int getDimension(int index) {
+ /** @param name attribute name, used for error reporting. */
+ private int getDimension(int index, @Nullable String name) {
String s = getString(index);
if (s == null) {
+ if (name != null) {
+ throw new RuntimeException("Attribute '" + name + "' not found");
+ }
throw new RuntimeException();
}
// Check if the value is a magic constant that doesn't require a unit.
@@ -758,6 +763,17 @@ public final class BridgeTypedArray extends TypedArray {
return s != null && ResourceHelper.parseFloatAttribute(mNames[index], s, outValue, false);
}
+ @Override
+ public int getType(int index) {
+ if (!hasValue(index)) {
+ return TypedValue.TYPE_NULL;
+ }
+ ResourceValue value = mResourceData[index];
+ ResourceType resourceType = value.getResourceType();
+ return 0;
+ // TODO: fixme.
+ }
+
/**
* Determines whether there is an attribute at <var>index</var>.
*
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
index 4bd83e9..41d94b7 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -27,6 +27,7 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
+import android.content.res.Resources.ThemeKey;
import android.util.AttributeSet;
import android.util.TypedValue;
@@ -110,22 +111,16 @@ public class Resources_Theme_Delegate {
private static boolean setupResources(Theme thisTheme) {
// Key is a space-separated list of theme ids applied that have been merged into the
// BridgeContext's theme to make thisTheme.
- String[] appliedStyles = thisTheme.getKey().split(" ");
+ final ThemeKey key = thisTheme.getKey();
+ final int[] resId = key.mResId;
+ final boolean[] force = key.mForce;
+
boolean changed = false;
- for (String s : appliedStyles) {
- if (s.isEmpty()) {
- continue;
- }
- // See the definition of force parameter in Theme.applyStyle().
- boolean force = false;
- if (s.charAt(s.length() - 1) == '!') {
- force = true;
- s = s.substring(0, s.length() - 1);
- }
- int styleId = Integer.parseInt(s, 16);
- StyleResourceValue style = resolveStyle(styleId);
+ for (int i = 0, N = key.mCount; i < N; i++) {
+ StyleResourceValue style = resolveStyle(resId[i]);
if (style != null) {
- RenderSessionImpl.getCurrentContext().getRenderResources().applyStyle(style, force);
+ RenderSessionImpl.getCurrentContext().getRenderResources().applyStyle(
+ style, force[i]);
changed = true;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
index a4a3b7d..21f36ce 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -19,6 +19,12 @@ package android.graphics;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
+import android.graphics.Paint_Delegate.FontInfo;
+import android.icu.lang.UScript;
+import android.icu.lang.UScriptRun;
+import android.icu.text.Bidi;
+import android.icu.text.BidiRun;
+
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Toolkit;
@@ -29,13 +35,6 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
-import com.ibm.icu.lang.UScript;
-import com.ibm.icu.lang.UScriptRun;
-import com.ibm.icu.text.Bidi;
-import com.ibm.icu.text.BidiRun;
-
-import android.graphics.Paint_Delegate.FontInfo;
-
/**
* Render the text by breaking it into various scripts and using the right font for each script.
* Can be used to measure the text without actually drawing it.
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index e9b5d6e..af47aeb 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -23,7 +23,15 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
+import java.awt.PaintContext;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
+import java.awt.image.Raster;
/**
* Delegate implementing the native methods of android.graphics.BitmapShader
@@ -67,9 +75,9 @@ public class BitmapShader_Delegate extends Shader_Delegate {
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static long nativeCreate(long native_bitmap, int shaderTileModeX,
+ /*package*/ static long nativeCreate(Bitmap androidBitmap, int shaderTileModeX,
int shaderTileModeY) {
- Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap);
+ Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(androidBitmap);
if (bitmap == null) {
return 0;
}
@@ -83,17 +91,17 @@ public class BitmapShader_Delegate extends Shader_Delegate {
// ---- Private delegate/helper methods ----
- private BitmapShader_Delegate(java.awt.image.BufferedImage image,
+ private BitmapShader_Delegate(BufferedImage image,
TileMode tileModeX, TileMode tileModeY) {
mJavaPaint = new BitmapShaderPaint(image, tileModeX, tileModeY);
}
private class BitmapShaderPaint implements java.awt.Paint {
- private final java.awt.image.BufferedImage mImage;
+ private final BufferedImage mImage;
private final TileMode mTileModeX;
private final TileMode mTileModeY;
- BitmapShaderPaint(java.awt.image.BufferedImage image,
+ BitmapShaderPaint(BufferedImage image,
TileMode tileModeX, TileMode tileModeY) {
mImage = image;
mTileModeX = tileModeX;
@@ -101,29 +109,24 @@ public class BitmapShader_Delegate extends Shader_Delegate {
}
@Override
- public java.awt.PaintContext createContext(
- java.awt.image.ColorModel colorModel,
- java.awt.Rectangle deviceBounds,
- java.awt.geom.Rectangle2D userBounds,
- java.awt.geom.AffineTransform xform,
- java.awt.RenderingHints hints) {
-
- java.awt.geom.AffineTransform canvasMatrix;
+ public PaintContext createContext(ColorModel colorModel, Rectangle deviceBounds,
+ Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) {
+ AffineTransform canvasMatrix;
try {
canvasMatrix = xform.createInverse();
- } catch (java.awt.geom.NoninvertibleTransformException e) {
+ } catch (NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in BitmapShader", e, null /*data*/);
- canvasMatrix = new java.awt.geom.AffineTransform();
+ canvasMatrix = new AffineTransform();
}
- java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ AffineTransform localMatrix = getLocalMatrix();
try {
localMatrix = localMatrix.createInverse();
- } catch (java.awt.geom.NoninvertibleTransformException e) {
+ } catch (NoninvertibleTransformException e) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
"Unable to inverse matrix in BitmapShader", e, null /*data*/);
- localMatrix = new java.awt.geom.AffineTransform();
+ localMatrix = new AffineTransform();
}
if (!colorModel.isCompatibleRaster(mImage.getRaster())) {
@@ -134,16 +137,16 @@ public class BitmapShader_Delegate extends Shader_Delegate {
return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel);
}
- private class BitmapShaderContext implements java.awt.PaintContext {
+ private class BitmapShaderContext implements PaintContext {
- private final java.awt.geom.AffineTransform mCanvasMatrix;
- private final java.awt.geom.AffineTransform mLocalMatrix;
- private final java.awt.image.ColorModel mColorModel;
+ private final AffineTransform mCanvasMatrix;
+ private final AffineTransform mLocalMatrix;
+ private final ColorModel mColorModel;
public BitmapShaderContext(
- java.awt.geom.AffineTransform canvasMatrix,
- java.awt.geom.AffineTransform localMatrix,
- java.awt.image.ColorModel colorModel) {
+ AffineTransform canvasMatrix,
+ AffineTransform localMatrix,
+ ColorModel colorModel) {
mCanvasMatrix = canvasMatrix;
mLocalMatrix = localMatrix;
mColorModel = colorModel;
@@ -154,13 +157,13 @@ public class BitmapShader_Delegate extends Shader_Delegate {
}
@Override
- public java.awt.image.ColorModel getColorModel() {
+ public ColorModel getColorModel() {
return mColorModel;
}
@Override
- public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(
+ public Raster getRaster(int x, int y, int w, int h) {
+ BufferedImage image = new BufferedImage(
mColorModel, mColorModel.createCompatibleWritableRaster(w, h),
mColorModel.isAlphaPremultiplied(), null);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 8d24d38..874bc9d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -16,6 +16,7 @@
package android.graphics;
+import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
@@ -76,19 +77,18 @@ public final class Bitmap_Delegate {
// ---- Public Helper methods ----
/**
- * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
- */
- public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
- return sManager.getDelegate(bitmap.mNativeBitmap);
- }
-
- /**
* Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
*/
public static Bitmap_Delegate getDelegate(long native_bitmap) {
return sManager.getDelegate(native_bitmap);
}
+ @Nullable
+ public static Bitmap_Delegate getDelegate(@Nullable Bitmap bitmap) {
+ // refSkPixelRef is a hack to get the native pointer: see #nativeRefPixelRef()
+ return bitmap == null ? null : getDelegate(bitmap.refSkPixelRef());
+ }
+
/**
* Creates and returns a {@link Bitmap} initialized with the given file content.
*
@@ -187,31 +187,7 @@ public final class Bitmap_Delegate {
return createBitmap(delegate, createFlags, density.getDpiValue());
}
- /**
- * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
- */
- public static BufferedImage getImage(Bitmap bitmap) {
- // get the delegate from the native int.
- Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
- if (delegate == null) {
- return null;
- }
-
- return delegate.mImage;
- }
-
- public static int getBufferedImageType(int nativeBitmapConfig) {
- switch (Config.nativeToConfig(nativeBitmapConfig)) {
- case ALPHA_8:
- return BufferedImage.TYPE_INT_ARGB;
- case RGB_565:
- return BufferedImage.TYPE_INT_ARGB;
- case ARGB_4444:
- return BufferedImage.TYPE_INT_ARGB;
- case ARGB_8888:
- return BufferedImage.TYPE_INT_ARGB;
- }
-
+ private static int getBufferedImageType() {
return BufferedImage.TYPE_INT_ARGB;
}
@@ -238,10 +214,6 @@ public final class Bitmap_Delegate {
return mHasAlpha && mConfig != Config.RGB_565;
}
- public boolean hasMipMap() {
- // TODO: check if more checks are required as in hasAlpha.
- return mHasMipMap;
- }
/**
* Update the generationId.
*
@@ -256,7 +228,7 @@ public final class Bitmap_Delegate {
@LayoutlibDelegate
/*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
int height, int nativeConfig, boolean isMutable) {
- int imageType = getBufferedImageType(nativeConfig);
+ int imageType = getBufferedImageType();
// create the image
BufferedImage image = new BufferedImage(width, height, imageType);
@@ -284,7 +256,7 @@ public final class Bitmap_Delegate {
int width = srcImage.getWidth();
int height = srcImage.getHeight();
- int imageType = getBufferedImageType(nativeConfig);
+ int imageType = getBufferedImageType();
// create the image
BufferedImage image = new BufferedImage(width, height, imageType);
@@ -373,22 +345,16 @@ public final class Bitmap_Delegate {
/*package*/ static boolean nativeHasAlpha(long nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
- if (delegate == null) {
- return true;
- }
+ return delegate == null || delegate.mHasAlpha;
- return delegate.mHasAlpha;
}
@LayoutlibDelegate
/*package*/ static boolean nativeHasMipMap(long nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
- if (delegate == null) {
- return true;
- }
+ return delegate == null || delegate.mHasMipMap;
- return delegate.mHasMipMap;
}
@LayoutlibDelegate
@@ -509,11 +475,6 @@ public final class Bitmap_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativePrepareToDraw(long nativeBitmap) {
- // nothing to be done here.
- }
-
- @LayoutlibDelegate
/*package*/ static boolean nativeIsPremultiplied(long nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -599,6 +560,14 @@ public final class Bitmap_Delegate {
return Arrays.equals(argb1, argb2);
}
+ // Only used by AssetAtlasService, which we don't care about.
+ @LayoutlibDelegate
+ /*package*/ static long nativeRefPixelRef(long nativeBitmap) {
+ // Hack: This is called by Bitmap.refSkPixelRef() and LayoutLib uses that method to get
+ // the native pointer from a Bitmap. So, we return nativeBitmap here.
+ return nativeBitmap;
+ }
+
// ---- Private delegate/helper methods ----
private Bitmap_Delegate(BufferedImage image, Config config) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 4d2d100..47acc42 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -16,6 +16,7 @@
package android.graphics;
+import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
@@ -114,7 +115,11 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long initRaster(long nativeBitmapOrZero) {
+ /*package*/ static long initRaster(@Nullable Bitmap bitmap) {
+ long nativeBitmapOrZero = 0;
+ if (bitmap != null) {
+ nativeBitmapOrZero = bitmap.refSkPixelRef();
+ }
if (nativeBitmapOrZero > 0) {
// get the Bitmap from the int
Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
@@ -132,8 +137,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/
- static void native_setBitmap(long canvas, long bitmap, boolean copyState) {
+ /*package*/ static void native_setBitmap(long canvas, Bitmap bitmap) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
if (canvasDelegate == null || bitmapDelegate==null) {
@@ -220,7 +224,8 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_restore(long nativeCanvas) {
+ /*package*/ static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
+ // FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -231,7 +236,9 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount) {
+ /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount,
+ boolean throwOnUnderflow) {
+ // FIXME: implement throwOnUnderflow.
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
@@ -424,8 +431,7 @@ public final class Canvas_Delegate {
canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
- if (canvasDelegate.mDrawFilter != null &&
- canvasDelegate.mDrawFilter.isSupported() == false) {
+ if (canvasDelegate.mDrawFilter != null && !canvasDelegate.mDrawFilter.isSupported()) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
}
@@ -441,7 +447,7 @@ public final class Canvas_Delegate {
}
Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
- if (rect != null && rect.isEmpty() == false) {
+ if (rect != null && !rect.isEmpty()) {
bounds.left = rect.x;
bounds.top = rect.y;
bounds.right = rect.x + rect.width;
@@ -717,7 +723,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap,
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
float left, float top,
long nativePaintOrZero,
int canvasDensity,
@@ -739,7 +745,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap,
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom,
long nativePaintOrZero, int screenDensity, int bitmapDensity) {
@@ -780,7 +786,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeDrawBitmapMatrix(long nCanvas, long nBitmap,
+ /*package*/ static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap,
long nMatrix, long nPaint) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
@@ -792,7 +798,7 @@ public final class Canvas_Delegate {
Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
// get the delegate from the native int.
- Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
if (bitmapDelegate == null) {
return;
}
@@ -821,7 +827,7 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeDrawBitmapMesh(long nCanvas, long nBitmap,
+ /*package*/ static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap,
int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
int colorOffset, long nPaint) {
// FIXME
@@ -844,7 +850,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count,
float startX, float startY, int flags, long paint, long typeface) {
- drawText(nativeCanvas, text, index, count, startX, startY, flags == Canvas.DIRECTION_RTL,
+ drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0,
paint, typeface);
}
@@ -1038,8 +1044,7 @@ public final class Canvas_Delegate {
}
/**
- * Restores the {@link GcSnapshot} to <var>saveCount</var>
- * @param saveCount the saveCount
+ * Restores the top {@link GcSnapshot}
*/
private void restore() {
mSnapshot = mSnapshot.restore();
@@ -1102,7 +1107,7 @@ public final class Canvas_Delegate {
// before drawing it.
if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
fixAlpha8Bitmap(image);
- } else if (bitmap.hasAlpha() == false) {
+ } else if (!bitmap.hasAlpha()) {
// hasAlpha is merely a rendering hint. There can in fact be alpha values
// in the bitmap but it should be ignored at drawing time.
// There is two ways to do this:
@@ -1122,7 +1127,7 @@ public final class Canvas_Delegate {
}
// if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
- if (forceSrcMode[0] == false) {
+ if (!forceSrcMode[0]) {
image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
}
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index e16dbda..e8d34d0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -90,7 +90,7 @@ public final class NinePatch_Delegate {
if (oos != null) {
try {
oos.close();
- } catch (IOException e) {
+ } catch (IOException ignored) {
}
}
}
@@ -136,7 +136,7 @@ public final class NinePatch_Delegate {
if (ois != null) {
try {
ois.close();
- } catch (IOException e) {
+ } catch (IOException ignored) {
}
}
}
@@ -150,15 +150,12 @@ public final class NinePatch_Delegate {
@LayoutlibDelegate
/*package*/ static boolean isNinePatchChunk(byte[] chunk) {
NinePatchChunk chunkObject = getChunk(chunk);
- if (chunkObject != null) {
- return true;
- }
+ return chunkObject != null;
- return false;
}
@LayoutlibDelegate
- /*package*/ static long validateNinePatchChunk(long bitmap, byte[] chunk) {
+ /*package*/ static long validateNinePatchChunk(byte[] chunk) {
// the default JNI implementation only checks that the byte[] has the same
// size as the C struct it represent. Since we cannot do the same check (serialization
// will return different size depending on content), we do nothing.
@@ -173,7 +170,7 @@ public final class NinePatch_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance,
+ /*package*/ static void nativeDraw(long canvas_instance, RectF loc, Bitmap bitmap_instance,
long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
(int) loc.left, (int) loc.top, (int) loc.right, (int) loc.bottom,
@@ -182,7 +179,7 @@ public final class NinePatch_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance,
+ /*package*/ static void nativeDraw(long canvas_instance, Rect loc, Bitmap bitmap_instance,
long chunk, long paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
loc.left, loc.top, loc.right, loc.bottom,
@@ -191,7 +188,7 @@ public final class NinePatch_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long nativeGetTransparentRegion(long bitmap, long chunk, Rect location) {
+ /*package*/ static long nativeGetTransparentRegion(Bitmap bitmap, long chunk, Rect location) {
return 0;
}
@@ -199,7 +196,7 @@ public final class NinePatch_Delegate {
private static void draw(long canvas_instance,
final int left, final int top, final int right, final int bottom,
- long bitmap_instance, long chunk, long paint_instance_or_null,
+ Bitmap bitmap_instance, long chunk, long paint_instance_or_null,
final int destDensity, final int srcDensity) {
// get the delegate from the native int.
final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 7b07404..3b1e3f9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -16,6 +16,8 @@
package android.graphics;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
@@ -83,6 +85,8 @@ public class Paint_Delegate {
private float mTextScaleX;
private float mTextSkewX;
private int mHintingMode = Paint.HINTING_ON;
+ private int mHyphenEdit;
+ private float mLetterSpacing; // not used in actual text rendering.
// Variant of the font. A paint's variant can only be compact or elegant.
private FontVariant mFontVariant = FontVariant.COMPACT;
@@ -100,6 +104,7 @@ public class Paint_Delegate {
// ---- Public Helper methods ----
+ @Nullable
public static Paint_Delegate getDelegate(long native_paint) {
return sManager.getDelegate(native_paint);
}
@@ -251,7 +256,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getFlags(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -264,7 +269,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setFlags(Paint thisPaint, int flags) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -280,7 +285,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getHinting(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return Paint.HINTING_ON;
}
@@ -291,7 +296,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setHinting(Paint thisPaint, int mode) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -337,7 +342,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getColor(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -348,7 +353,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setColor(Paint thisPaint, int color) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -359,7 +364,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getAlpha(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -370,7 +375,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setAlpha(Paint thisPaint, int a) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -381,7 +386,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getStrokeWidth(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -392,7 +397,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -403,7 +408,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getStrokeMiter(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -414,7 +419,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -441,14 +446,14 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
}
@LayoutlibDelegate
/*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -459,7 +464,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getTextSize(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -470,7 +475,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setTextSize(Paint thisPaint, float textSize) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -482,7 +487,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getTextScaleX(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -493,7 +498,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -505,7 +510,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getTextSkewX(Paint thisPaint) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 1.f;
}
@@ -516,7 +521,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
@@ -528,7 +533,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float ascent(Paint thisPaint) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -545,7 +550,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float descent(Paint thisPaint) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -562,7 +567,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -573,7 +578,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -599,7 +604,7 @@ public class Paint_Delegate {
/*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
int count, int bidiFlags) {
// get the delegate
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return 0;
}
@@ -1088,18 +1093,107 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float native_getLetterSpacing(long nativePaint) {
- // TODO: throw a fidelity warning.
- return 0;
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+ return delegate.mLetterSpacing;
}
@LayoutlibDelegate
/*package*/ static void native_setLetterSpacing(long nativePaint, float letterSpacing) {
- // pass.
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
+ "Paint.setLetterSpacing() not supported.", null, null);
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return;
+ }
+ delegate.mLetterSpacing = letterSpacing;
}
@LayoutlibDelegate
/*package*/ static void native_setFontFeatureSettings(long nativePaint, String settings) {
- // pass.
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
+ "Paint.setFontFeatureSettings() not supported.", null, null);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getHyphenEdit(long nativePaint) {
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+ return delegate.mHyphenEdit;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setHyphenEdit(long nativePaint, int hyphen) {
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return;
+ }
+ delegate.mHyphenEdit = hyphen;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_hasGlyph(long nativePaint, long nativeTypeface, int bidiFlags,
+ String string) {
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return false;
+ }
+ if (string.length() == 0) {
+ return false;
+ }
+ if (string.length() > 1) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
+ "Paint.hasGlyph() is not supported for ligatures.", null, null);
+ return false;
+ }
+ assert nativeTypeface == delegate.mNativeTypeface;
+ Typeface_Delegate typeface_delegate = Typeface_Delegate.getDelegate(nativeTypeface);
+
+ char c = string.charAt(0);
+ for (Font font : typeface_delegate.getFonts(delegate.mFontVariant)) {
+ if (font.canDisplay(c)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static float native_getRunAdvance(long nativePaint, long nativeTypeface,
+ @NonNull char[] text, int start, int end, int contextStart, int contextEnd,
+ boolean isRtl, int offset) {
+ int count = end - start;
+ float[] advances = new float[count];
+ native_getTextRunAdvances(nativePaint, nativeTypeface, text, start, count,
+ contextStart, contextEnd - contextStart, isRtl, advances, 0);
+ float sum = 0;
+ for (int i = 0; i < offset; i++) {
+ sum += advances[i];
+ }
+ return sum;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getOffsetForAdvance(long nativePaint, long nativeTypeface,
+ char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl,
+ float advance) {
+ int count = end - start;
+ float[] advances = new float[count];
+ native_getTextRunAdvances(nativePaint, nativeTypeface, text, start, count,
+ contextStart, contextEnd - contextStart, isRtl, advances, 0);
+ float sum = 0;
+ int i;
+ for (i = 0; i < count && sum < advance; i++) {
+ sum += advances[i];
+ }
+ float distanceToI = sum - advance;
+ float distanceToIMinus1 = advance - (sum - advances[i]);
+ return distanceToI > distanceToIMinus1 ? i : i - 1;
}
// ---- Private delegate/helper methods ----
@@ -1137,7 +1231,7 @@ public class Paint_Delegate {
}
private void reset() {
- mFlags = Paint.DEFAULT_PAINT_FLAGS;
+ mFlags = Paint.HIDDEN_DEFAULT_PAINT_FLAGS;
mColor = 0xFF000000;
mStyle = Paint.Style.FILL.nativeInt;
mCap = Paint.Cap.BUTT.nativeInt;
@@ -1232,7 +1326,7 @@ public class Paint_Delegate {
private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
// get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
if (delegate == null) {
return;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
index 14e9960..0d491a0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -81,14 +81,15 @@ public abstract class Shader_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeSetLocalMatrix(long native_shader, long matrix_instance) {
+ /*package*/ static long nativeSetLocalMatrix(long native_shader, long matrix_instance) {
// get the delegate from the native int.
Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
if (shaderDelegate == null) {
- return;
+ return native_shader;
}
shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance);
+ return native_shader;
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
index 6247dae..38171dc 100644
--- a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
@@ -19,8 +19,8 @@ package android.text;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-import com.ibm.icu.text.Bidi;
+import android.icu.text.Bidi;
/**
* Delegate used to provide new implementation for the native methods of {@link AndroidBidi}
diff --git a/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
new file mode 100644
index 0000000..b95cda6
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import com.android.annotations.NonNull;
+
+import android.text.Primitive.PrimitiveType;
+import android.text.StaticLayout.LineBreaks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.text.Primitive.PrimitiveType.PENALTY_INFINITY;
+
+// Based on the native implementation of GreedyLineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class GreedyLineBreaker extends LineBreaker {
+
+ public GreedyLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+ @NonNull TabStops tabStops) {
+ super(primitives, lineWidth, tabStops);
+ }
+
+ @Override
+ public void computeBreaks(@NonNull LineBreaks lineBreaks) {
+ BreakInfo breakInfo = new BreakInfo();
+ int lineNum = 0;
+ float width = 0, printedWidth = 0;
+ boolean breakFound = false, goodBreakFound = false;
+ int breakIndex = 0, goodBreakIndex = 0;
+ float breakWidth = 0, goodBreakWidth = 0;
+ int firstTabIndex = Integer.MAX_VALUE;
+
+ float maxWidth = mLineWidth.getLineWidth(lineNum);
+
+ int numPrimitives = mPrimitives.size();
+ // greedily fit as many characters as possible on each line
+ // loop over all primitives, and choose the best break point
+ // (if possible, a break point without splitting a word)
+ // after going over the maximum length
+ for (int i = 0; i < numPrimitives; i++) {
+ Primitive p = mPrimitives.get(i);
+
+ // update the current line width
+ if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+ width += p.width;
+ if (p.type == PrimitiveType.BOX) {
+ printedWidth = width;
+ }
+ } else if (p.type == PrimitiveType.VARIABLE) {
+ width = mTabStops.width(width);
+ // keep track of first tab character in the region we are examining
+ // so we can determine whether or not a line contains a tab
+ firstTabIndex = Math.min(firstTabIndex, i);
+ }
+
+ // find the best break point for the characters examined so far
+ if (printedWidth > maxWidth) {
+ //noinspection StatementWithEmptyBody
+ if (breakFound || goodBreakFound) {
+ if (goodBreakFound) {
+ // a true line break opportunity existed in the characters examined so far,
+ // so there is no need to split a word
+ i = goodBreakIndex; // no +1 because of i++
+ lineNum++;
+ maxWidth = mLineWidth.getLineWidth(lineNum);
+ breakInfo.mBreaksList.add(mPrimitives.get(goodBreakIndex).location);
+ breakInfo.mWidthsList.add(goodBreakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < goodBreakIndex);
+ firstTabIndex = Integer.MAX_VALUE;
+ } else {
+ // must split a word because there is no other option
+ i = breakIndex; // no +1 because of i++
+ lineNum++;
+ maxWidth = mLineWidth.getLineWidth(lineNum);
+ breakInfo.mBreaksList.add(mPrimitives.get(breakIndex).location);
+ breakInfo.mWidthsList.add(breakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < breakIndex);
+ firstTabIndex = Integer.MAX_VALUE;
+ }
+ printedWidth = width = 0;
+ goodBreakFound = breakFound = false;
+ goodBreakWidth = breakWidth = 0;
+ continue;
+ } else {
+ // no choice, keep going... must make progress by putting at least one
+ // character on a line, even if part of that character is cut off --
+ // there is no other option
+ }
+ }
+
+ // update possible break points
+ if (p.type == PrimitiveType.PENALTY &&
+ p.penalty < PENALTY_INFINITY) {
+ // this does not handle penalties with width
+
+ // handle forced line break
+ if (p.penalty == -PENALTY_INFINITY) {
+ lineNum++;
+ maxWidth = mLineWidth.getLineWidth(lineNum);
+ breakInfo.mBreaksList.add(p.location);
+ breakInfo.mWidthsList.add(printedWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < i);
+ firstTabIndex = Integer.MAX_VALUE;
+ printedWidth = width = 0;
+ goodBreakFound = breakFound = false;
+ goodBreakWidth = breakWidth = 0;
+ continue;
+ }
+ if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
+ breakFound = true;
+ breakIndex = i;
+ breakWidth = printedWidth;
+ }
+ if (i > goodBreakIndex && printedWidth <= maxWidth) {
+ goodBreakFound = true;
+ goodBreakIndex = i;
+ goodBreakWidth = printedWidth;
+ }
+ } else if (p.type == PrimitiveType.WORD_BREAK) {
+ // only do this if necessary -- we don't want to break words
+ // when possible, but sometimes it is unavoidable
+ if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
+ breakFound = true;
+ breakIndex = i;
+ breakWidth = printedWidth;
+ }
+ }
+ }
+
+ if (breakFound || goodBreakFound) {
+ // output last break if there are more characters to output
+ if (goodBreakFound) {
+ breakInfo.mBreaksList.add(mPrimitives.get(goodBreakIndex).location);
+ breakInfo.mWidthsList.add(goodBreakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < goodBreakIndex);
+ } else {
+ breakInfo.mBreaksList.add(mPrimitives.get(breakIndex).location);
+ breakInfo.mWidthsList.add(breakWidth);
+ breakInfo.mFlagsList.add(firstTabIndex < breakIndex);
+ }
+ }
+ breakInfo.copyTo(lineBreaks);
+ }
+
+ private static class BreakInfo {
+ List<Integer> mBreaksList = new ArrayList<Integer>();
+ List<Float> mWidthsList = new ArrayList<Float>();
+ List<Boolean> mFlagsList = new ArrayList<Boolean>();
+
+ public void copyTo(LineBreaks lineBreaks) {
+ if (lineBreaks.breaks.length != mBreaksList.size()) {
+ lineBreaks.breaks = new int[mBreaksList.size()];
+ lineBreaks.widths = new float[mWidthsList.size()];
+ lineBreaks.flags = new int[mFlagsList.size()];
+ }
+
+ int i = 0;
+ for (int b : mBreaksList) {
+ lineBreaks.breaks[i] = b;
+ i++;
+ }
+ i = 0;
+ for (float b : mWidthsList) {
+ lineBreaks.widths[i] = b;
+ i++;
+ }
+ i = 0;
+ for (boolean b : mFlagsList) {
+ lineBreaks.flags[i] = b ? TAB_MASK : 0;
+ i++;
+ }
+
+ mBreaksList = null;
+ mWidthsList = null;
+ mFlagsList = null;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
new file mode 100644
index 0000000..5a59597
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.io.File;
+
+/**
+ * Delegate that overrides implementation for certain methods in {@link android.text.StaticLayout}
+ * <p/>
+ * Through the layoutlib_create tool, selected methods of StaticLayout have been replaced
+ * by calls to methods of the same name in this delegate class.
+ */
+public class Hyphenator_Delegate {
+
+ private static final DelegateManager<Hyphenator_Delegate> sDelegateManager = new
+ DelegateManager<Hyphenator_Delegate>(Hyphenator_Delegate.class);
+
+ @LayoutlibDelegate
+ /*package*/ static File getSystemHyphenatorLocation() {
+ // FIXME
+ return null;
+ }
+
+ /*package*/ static long loadHyphenator(String patternData) {
+ return sDelegateManager.addNewDelegate(new Hyphenator_Delegate());
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/LineBreaker.java b/tools/layoutlib/bridge/src/android/text/LineBreaker.java
new file mode 100644
index 0000000..edeef78
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/LineBreaker.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import android.text.StaticLayout.LineBreaks;
+import com.android.annotations.NonNull;
+
+import java.util.Collections;
+import java.util.List;
+
+// Based on the native implementation of LineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public abstract class LineBreaker {
+
+ protected static final int TAB_MASK = 0x20000000; // keep in sync with StaticLayout
+
+ protected final @NonNull List<Primitive> mPrimitives;
+ protected final @NonNull LineWidth mLineWidth;
+ protected final @NonNull TabStops mTabStops;
+
+ public LineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+ @NonNull TabStops tabStops) {
+ mPrimitives = Collections.unmodifiableList(primitives);
+ mLineWidth = lineWidth;
+ mTabStops = tabStops;
+ }
+
+ public abstract void computeBreaks(@NonNull LineBreaks breakInfo);
+}
diff --git a/tools/layoutlib/bridge/src/android/text/LineWidth.java b/tools/layoutlib/bridge/src/android/text/LineWidth.java
new file mode 100644
index 0000000..2ea886d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/LineWidth.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+// Based on the native implementation of LineWidth in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class LineWidth {
+ private final float mFirstWidth;
+ private final int mFirstWidthLineCount;
+ private float mRestWidth;
+
+ public LineWidth(float firstWidth, int firstWidthLineCount, float restWidth) {
+ mFirstWidth = firstWidth;
+ mFirstWidthLineCount = firstWidthLineCount;
+ mRestWidth = restWidth;
+ }
+
+ public float getLineWidth(int line) {
+ return (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
new file mode 100644
index 0000000..cd92581
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import com.android.annotations.NonNull;
+
+import android.text.Primitive.PrimitiveType;
+import android.text.StaticLayout.LineBreaks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import static android.text.Primitive.PrimitiveType.PENALTY_INFINITY;
+
+
+// Based on the native implementation of OptimizingLineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+/**
+ * A more complex version of line breaking where we try to prevent the right edge from being too
+ * jagged.
+ */
+public class OptimizingLineBreaker extends LineBreaker {
+
+ public OptimizingLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+ @NonNull TabStops tabStops) {
+ super(primitives, lineWidth, tabStops);
+ }
+
+ @Override
+ public void computeBreaks(@NonNull LineBreaks breakInfo) {
+ int numBreaks = mPrimitives.size();
+ assert numBreaks > 0;
+ if (numBreaks == 1) {
+ // This can be true only if it's an empty paragraph.
+ Primitive p = mPrimitives.get(0);
+ assert p.type == PrimitiveType.PENALTY;
+ breakInfo.breaks = new int[]{0};
+ breakInfo.widths = new float[]{p.width};
+ breakInfo.flags = new int[]{0};
+ return;
+ }
+ Node[] opt = new Node[numBreaks];
+ opt[0] = new Node(-1, 0, 0, 0, false);
+ opt[numBreaks - 1] = new Node(-1, 0, 0, 0, false);
+
+ ArrayList<Integer> active = new ArrayList<Integer>();
+ active.add(0);
+ int lastBreak = 0;
+ for (int i = 0; i < numBreaks; i++) {
+ Primitive p = mPrimitives.get(i);
+ if (p.type == PrimitiveType.PENALTY) {
+ boolean finalBreak = (i + 1 == numBreaks);
+ Node bestBreak = null;
+
+ for (ListIterator<Integer> it = active.listIterator(); it.hasNext();
+ /* incrementing done in loop */) {
+ int pos = it.next();
+ int lines = opt[pos].mPrevCount;
+ float maxWidth = mLineWidth.getLineWidth(lines);
+ // we have to compute metrics every time --
+ // we can't really pre-compute this stuff and just deal with breaks
+ // because of the way tab characters work, this makes it computationally
+ // harder, but this way, we can still optimize while treating tab characters
+ // correctly
+ LineMetrics lineMetrics = computeMetrics(pos, i);
+ if (lineMetrics.mPrintedWidth <= maxWidth) {
+ float demerits = computeDemerits(maxWidth, lineMetrics.mPrintedWidth,
+ finalBreak, p.penalty) + opt[pos].mDemerits;
+ if (bestBreak == null || demerits < bestBreak.mDemerits) {
+ if (bestBreak == null) {
+ bestBreak = new Node(pos, opt[pos].mPrevCount + 1, demerits,
+ lineMetrics.mPrintedWidth, lineMetrics.mHasTabs);
+ } else {
+ bestBreak.mPrev = pos;
+ bestBreak.mPrevCount = opt[pos].mPrevCount + 1;
+ bestBreak.mDemerits = demerits;
+ bestBreak.mWidth = lineMetrics.mPrintedWidth;
+ bestBreak.mHasTabs = lineMetrics.mHasTabs;
+ }
+ }
+ } else {
+ it.remove();
+ }
+ }
+ if (p.penalty == -PENALTY_INFINITY) {
+ active.clear();
+ }
+ if (bestBreak != null) {
+ opt[i] = bestBreak;
+ active.add(i);
+ lastBreak = i;
+ }
+ if (active.isEmpty()) {
+ // we can't give up!
+ LineMetrics lineMetrics = new LineMetrics();
+ int lines = opt[lastBreak].mPrevCount;
+ float maxWidth = mLineWidth.getLineWidth(lines);
+ int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, lineMetrics);
+ opt[breakIndex] = new Node(lastBreak, lines + 1, 0 /*doesn't matter*/,
+ lineMetrics.mWidth, lineMetrics.mHasTabs);
+ active.add(breakIndex);
+ lastBreak = breakIndex;
+ i = breakIndex; // incremented by i++
+ }
+ }
+ }
+
+ int idx = numBreaks - 1;
+ int count = opt[idx].mPrevCount;
+ resize(breakInfo, count);
+ while (opt[idx].mPrev != -1) {
+ count--;
+ assert count >=0;
+
+ breakInfo.breaks[count] = mPrimitives.get(idx).location;
+ breakInfo.widths[count] = opt[idx].mWidth;
+ breakInfo.flags [count] = opt[idx].mHasTabs ? TAB_MASK : 0;
+ idx = opt[idx].mPrev;
+ }
+ }
+
+ private static void resize(LineBreaks lineBreaks, int size) {
+ if (lineBreaks.breaks.length == size) {
+ return;
+ }
+ int[] breaks = new int[size];
+ float[] widths = new float[size];
+ int[] flags = new int[size];
+
+ int toCopy = Math.min(size, lineBreaks.breaks.length);
+ System.arraycopy(lineBreaks.breaks, 0, breaks, 0, toCopy);
+ System.arraycopy(lineBreaks.widths, 0, widths, 0, toCopy);
+ System.arraycopy(lineBreaks.flags, 0, flags, 0, toCopy);
+
+ lineBreaks.breaks = breaks;
+ lineBreaks.widths = widths;
+ lineBreaks.flags = flags;
+ }
+
+ @NonNull
+ private LineMetrics computeMetrics(int start, int end) {
+ boolean f = false;
+ float w = 0, pw = 0;
+ for (int i = start; i < end; i++) {
+ Primitive p = mPrimitives.get(i);
+ if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+ w += p.width;
+ if (p.type == PrimitiveType.BOX) {
+ pw = w;
+ }
+ } else if (p.type == PrimitiveType.VARIABLE) {
+ w = mTabStops.width(w);
+ f = true;
+ }
+ }
+ return new LineMetrics(w, pw, f);
+ }
+
+ private static float computeDemerits(float maxWidth, float width, boolean finalBreak,
+ float penalty) {
+ float deviation = finalBreak ? 0 : maxWidth - width;
+ return (deviation * deviation) + penalty;
+ }
+
+ /**
+ * @return the last break position or -1 if failed.
+ */
+ @SuppressWarnings("ConstantConditions") // method too complex to be analyzed.
+ private int desperateBreak(int start, int limit, float maxWidth,
+ @NonNull LineMetrics lineMetrics) {
+ float w = 0, pw = 0;
+ boolean breakFound = false;
+ int breakIndex = 0, firstTabIndex = Integer.MAX_VALUE;
+ for (int i = start; i < limit; i++) {
+ Primitive p = mPrimitives.get(i);
+
+ if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+ w += p.width;
+ if (p.type == PrimitiveType.BOX) {
+ pw = w;
+ }
+ } else if (p.type == PrimitiveType.VARIABLE) {
+ w = mTabStops.width(w);
+ firstTabIndex = Math.min(firstTabIndex, i);
+ }
+
+ if (pw > maxWidth && breakFound) {
+ break;
+ }
+
+ // must make progress
+ if (i > start &&
+ (p.type == PrimitiveType.PENALTY || p.type == PrimitiveType.WORD_BREAK)) {
+ breakFound = true;
+ breakIndex = i;
+ }
+ }
+
+ if (breakFound) {
+ lineMetrics.mWidth = w;
+ lineMetrics.mPrintedWidth = pw;
+ lineMetrics.mHasTabs = (start <= firstTabIndex && firstTabIndex < breakIndex);
+ return breakIndex;
+ } else {
+ return -1;
+ }
+ }
+
+ private static class LineMetrics {
+ /** Actual width of the line. */
+ float mWidth;
+ /** Width of the line minus trailing whitespace. */
+ float mPrintedWidth;
+ boolean mHasTabs;
+
+ public LineMetrics() {
+ }
+
+ public LineMetrics(float width, float printedWidth, boolean hasTabs) {
+ mWidth = width;
+ mPrintedWidth = printedWidth;
+ mHasTabs = hasTabs;
+ }
+ }
+
+ /**
+ * A struct to store the info about a break.
+ */
+ @SuppressWarnings("SpellCheckingInspection") // For the word struct.
+ private static class Node {
+ // -1 for the first node.
+ int mPrev;
+ // number of breaks so far.
+ int mPrevCount;
+ float mDemerits;
+ float mWidth;
+ boolean mHasTabs;
+
+ public Node(int prev, int prevCount, float demerits, float width, boolean hasTabs) {
+ mPrev = prev;
+ mPrevCount = prevCount;
+ mDemerits = demerits;
+ mWidth = width;
+ mHasTabs = hasTabs;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/Primitive.java b/tools/layoutlib/bridge/src/android/text/Primitive.java
new file mode 100644
index 0000000..ce77601
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/Primitive.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import com.android.annotations.NonNull;
+
+// Based on the native implementation of Primitive in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class Primitive {
+ public final @NonNull PrimitiveType type;
+ public final int location;
+ // The following fields don't make sense for all types.
+ // Box and Glue have width only.
+ // Penalty has both width and penalty.
+ // Word_break has penalty only.
+ public final float width;
+ public final float penalty;
+
+ /**
+ * Use {@code PrimitiveType#getNewPrimitive()}
+ */
+ private Primitive(@NonNull PrimitiveType type, int location, float width, float penalty) {
+ this.type = type;
+ this.location = location;
+ this.width = width;
+ this.penalty = penalty;
+ }
+
+ public static enum PrimitiveType {
+ /**
+ * Something with a constant width that is to be typeset - like a character.
+ */
+ BOX,
+ /**
+ * Blank space with fixed width.
+ */
+ GLUE,
+ /**
+ * Aesthetic cost indicating how desirable breaking at this point will be. A penalty of
+ * {@link #PENALTY_INFINITY} means a forced non-break, whereas a penalty of negative
+ * {@code #PENALTY_INFINITY} means a forced break.
+ * <p/>
+ * Currently, it only stores penalty with values 0 or -infinity.
+ */
+ PENALTY,
+ /**
+ * For tabs - variable width space.
+ */
+ VARIABLE,
+ /**
+ * Possible breakpoints within a word. Think of this as a high cost {@link #PENALTY}.
+ */
+ WORD_BREAK;
+
+ public Primitive getNewPrimitive(int location) {
+ assert this == VARIABLE;
+ return new Primitive(this, location, 0f, 0f);
+ }
+
+ public Primitive getNewPrimitive(int location, float value) {
+ assert this == BOX || this == GLUE || this == WORD_BREAK;
+ if (this == BOX || this == GLUE) {
+ return new Primitive(this, location, value, 0f);
+ } else {
+ return new Primitive(this, location, 0f, value);
+ }
+ }
+
+ public Primitive getNewPrimitive(int location, float width, float penalty) {
+ assert this == PENALTY;
+ return new Primitive(this, location, width, penalty);
+ }
+
+ // forced non-break, negative infinity is forced break.
+ public static final float PENALTY_INFINITY = 1e7f;
+ }
+}
+
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index b0d79a8..4226526 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -1,14 +1,22 @@
package android.text;
+import com.android.annotations.NonNull;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-import java.text.CharacterIterator;
+import android.graphics.BidiRenderer;
+import android.graphics.Paint;
+import android.graphics.Paint_Delegate;
+import android.graphics.RectF;
+import android.icu.text.BreakIterator;
+import android.icu.util.ULocale;
+import android.text.Primitive.PrimitiveType;
+import android.text.StaticLayout.LineBreaks;
+
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Locale;
+import java.util.List;
-import com.ibm.icu.lang.UCharacter;
-import com.ibm.icu.text.BreakIterator;
-import com.ibm.icu.util.ULocale;
import javax.swing.text.Segment;
/**
@@ -20,36 +28,206 @@ import javax.swing.text.Segment;
*/
public class StaticLayout_Delegate {
+ private static final char CHAR_SPACE = 0x20;
+ private static final char CHAR_TAB = 0x09;
+ private static final char CHAR_NEWLINE = 0x0A;
+ private static final char CHAR_ZWSP = 0x200B; // Zero width space.
+
+ // ---- Builder delegate manager ----
+ private static final DelegateManager<Builder> sBuilderManager =
+ new DelegateManager<Builder>(Builder.class);
+
+ @LayoutlibDelegate
+ /*package*/ static long nNewBuilder() {
+ return sBuilderManager.addNewDelegate(new Builder());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nFreeBuilder(long nativeBuilder) {
+ sBuilderManager.removeJavaReferenceFor(nativeBuilder);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nFinishBuilder(long nativeBuilder) {
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static long nLoadHyphenator(String patternData) {
+ return Hyphenator_Delegate.loadHyphenator(patternData);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nSetLocale(long nativeBuilder, String locale, long nativeHyphenator) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ if (builder != null) {
+ builder.mLocale = locale;
+ builder.mNativeHyphenator = nativeHyphenator;
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nSetIndents(long nativeBuilder, int[] indents) {
+ // TODO.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nSetupParagraph(long nativeBuilder, char[] text, int length,
+ float firstWidth, int firstWidthLineCount, float restWidth,
+ int[] variableTabStops, int defaultTabStop, int breakStrategy,
+ int hyphenationFrequency) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ if (builder == null) {
+ return;
+ }
+
+ builder.mText = text;
+ builder.mWidths = new float[length];
+ builder.mLineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
+ builder.mTabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float nAddStyleRun(long nativeBuilder, long nativePaint, long nativeTypeface,
+ int start, int end, boolean isRtl) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+
+ int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
+ return builder == null ? 0 :
+ measureText(nativePaint, builder.mText, start, end - start, builder.mWidths,
+ bidiFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nAddMeasuredRun(long nativeBuilder, int start, int end, float[] widths) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ if (builder != null) {
+ System.arraycopy(widths, start, builder.mWidths, start, end - start);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nAddReplacementRun(long nativeBuilder, int start, int end, float width) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ if (builder == null) {
+ return;
+ }
+ builder.mWidths[start] = width;
+ Arrays.fill(builder.mWidths, start + 1, end, 0.0f);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nGetWidths(long nativeBuilder, float[] floatsArray) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ if (builder != null) {
+ System.arraycopy(builder.mWidths, 0, floatsArray, 0, builder.mWidths.length);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nComputeLineBreaks(long nativeBuilder,
+ LineBreaks recycle, int[] recycleBreaks, float[] recycleWidths,
+ int[] recycleFlags, int recycleLength) {
+
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ if (builder == null) {
+ return 0;
+ }
+
+ // compute all possible breakpoints.
+ int length = builder.mWidths.length;
+ BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
+ it.setText(new Segment(builder.mText, 0, length));
+
+ // average word length in english is 5. So, initialize the possible breaks with a guess.
+ List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
+ int loc;
+ it.first();
+ while ((loc = it.next()) != BreakIterator.DONE) {
+ breaks.add(loc);
+ }
+
+ List<Primitive> primitives =
+ computePrimitives(builder.mText, builder.mWidths, length, breaks);
+ switch (builder.mBreakStrategy) {
+ case Layout.BREAK_STRATEGY_SIMPLE:
+ builder.mLineBreaker = new GreedyLineBreaker(primitives, builder.mLineWidth,
+ builder.mTabStopCalculator);
+ break;
+ case Layout.BREAK_STRATEGY_HIGH_QUALITY:
+ // TODO
+// break;
+ case Layout.BREAK_STRATEGY_BALANCED:
+ builder.mLineBreaker = new OptimizingLineBreaker(primitives, builder.mLineWidth,
+ builder.mTabStopCalculator);
+ break;
+ default:
+ throw new AssertionError("Unknown break strategy: " + builder.mBreakStrategy);
+ }
+ builder.mLineBreaker.computeBreaks(recycle);
+ return recycle.breaks.length;
+ }
+
/**
- * Fills the recycle array with positions that are suitable to break the text at. The array
- * must be terminated by '-1'.
+ * Compute metadata each character - things which help in deciding if it's possible to break
+ * at a point or not.
*/
- @LayoutlibDelegate
- /*package*/ static int[] nLineBreakOpportunities(String locale, char[] text, int length,
- int[] recycle) {
- BreakIterator iterator = BreakIterator.getLineInstance(new ULocale(locale));
- Segment segment = new Segment(text, 0, length);
- iterator.setText(segment);
- if (recycle == null) {
- // Because 42 is the answer to everything.
- recycle = new int[42];
- }
- int breakOpp = iterator.first();
- recycle[0] = breakOpp;
- //noinspection ConstantConditions
- assert BreakIterator.DONE == -1;
- for (int i = 1; breakOpp != BreakIterator.DONE; ++i) {
- if (i >= recycle.length) {
- recycle = doubleSize(recycle);
+ @NonNull
+ private static List<Primitive> computePrimitives(@NonNull char[] text, @NonNull float[] widths,
+ int length, @NonNull List<Integer> breaks) {
+ // Initialize the list with a guess of the number of primitives:
+ // 2 Primitives per non-whitespace char and approx 5 chars per word (i.e. 83% chars)
+ List<Primitive> primitives = new ArrayList<Primitive>(((int) Math.ceil(length * 1.833)));
+ int breaksSize = breaks.size();
+ int breakIndex = 0;
+ for (int i = 0; i < length; i++) {
+ char c = text[i];
+ if (c == CHAR_SPACE || c == CHAR_ZWSP) {
+ primitives.add(PrimitiveType.GLUE.getNewPrimitive(i, widths[i]));
+ } else if (c == CHAR_TAB) {
+ primitives.add(PrimitiveType.VARIABLE.getNewPrimitive(i));
+ } else if (c != CHAR_NEWLINE) {
+ while (breakIndex < breaksSize && breaks.get(breakIndex) < i) {
+ breakIndex++;
+ }
+ Primitive p;
+ if (widths[i] != 0) {
+ if (breakIndex < breaksSize && breaks.get(breakIndex) == i) {
+ p = PrimitiveType.PENALTY.getNewPrimitive(i, 0, 0);
+ } else {
+ p = PrimitiveType.WORD_BREAK.getNewPrimitive(i, 0);
+ }
+ primitives.add(p);
+ }
+
+ primitives.add(PrimitiveType.BOX.getNewPrimitive(i, widths[i]));
}
- assert (i < recycle.length);
- breakOpp = iterator.next();
- recycle[i] = breakOpp;
}
- return recycle;
+ // final break at end of everything
+ primitives.add(
+ PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY));
+ return primitives;
}
- private static int[] doubleSize(int[] array) {
- return Arrays.copyOf(array, array.length * 2);
+ private static float measureText(long nativePaint, char []text, int index, int count,
+ float[] widths, int bidiFlags) {
+ Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
+ RectF bounds = new BidiRenderer(null, paint, text)
+ .renderText(index, index + count, bidiFlags, widths, 0, false);
+ return bounds.right - bounds.left;
+ }
+
+ // TODO: Rename to LineBreakerRef and move everything other than LineBreaker to LineBreaker.
+ /**
+ * Java representation of the native Builder class.
+ */
+ private static class Builder {
+ String mLocale;
+ char[] mText;
+ float[] mWidths;
+ LineBreaker mLineBreaker;
+ long mNativeHyphenator;
+ int mBreakStrategy;
+ LineWidth mLineWidth;
+ TabStops mTabStopCalculator;
}
}
diff --git a/tools/layoutlib/bridge/src/android/text/TabStops.java b/tools/layoutlib/bridge/src/android/text/TabStops.java
new file mode 100644
index 0000000..cff6b93
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/TabStops.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import com.android.annotations.Nullable;
+
+// Based on the native implementation of TabStops in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class TabStops {
+ @Nullable
+ private int[] mStops;
+ private final int mTabWidth;
+
+ public TabStops(@Nullable int[] stops, int defaultTabWidth) {
+ mTabWidth = defaultTabWidth;
+ mStops = stops;
+ }
+
+ public float width(float widthSoFar) {
+ if (mStops != null) {
+ for (int i : mStops) {
+ if (i > widthSoFar) {
+ return i;
+ }
+ }
+ }
+ // find the next tabStop after widthSoFar.
+ return (int) ((widthSoFar + mTabWidth) / mTabWidth) * mTabWidth;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java b/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java
index a193330..213e848 100644
--- a/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java
@@ -17,9 +17,9 @@
package android.util;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,11 +37,7 @@ public class Xml_Delegate {
@LayoutlibDelegate
/*package*/ static XmlPullParser newPullParser() {
try {
- KXmlParser parser = new KXmlParser();
- // The prebuilt kxml2 library with the IDE doesn't support DOCECL.
-// parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- return parser;
+ return ParserFactory.instantiateParser(null);
} catch (XmlPullParserException e) {
throw new AssertionError();
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 2e649c3..32ee9e8 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -53,9 +53,14 @@ public final class BridgeInflater extends LayoutInflater {
*/
private static final String[] sClassPrefixList = {
"android.widget.",
- "android.webkit."
+ "android.webkit.",
+ "android.app."
};
+ public static String[] getClassPrefixList() {
+ return sClassPrefixList;
+ }
+
protected BridgeInflater(LayoutInflater original, Context newContext) {
super(original, newContext);
newContext = getBaseContext(newContext);
@@ -127,11 +132,11 @@ public final class BridgeInflater extends LayoutInflater {
}
@Override
- public View createViewFromTag(View parent, String name, AttributeSet attrs,
- boolean inheritContext) {
+ public View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
+ boolean ignoreThemeAttrs) {
View view;
try {
- view = super.createViewFromTag(parent, name, attrs, inheritContext);
+ view = super.createViewFromTag(parent, name, context, attrs, ignoreThemeAttrs);
} catch (InflateException e) {
// try to load the class from using the custom view loader
try {
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 5176419..82012c1 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -17,6 +17,7 @@
package android.view;
import android.graphics.Point;
+import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -215,6 +216,12 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void overridePendingAppTransitionClipReveal(int startX, int startY,
+ int startWidth, int startHeight) throws RemoteException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
IRemoteCallback startedCallback, boolean scaleUp) throws RemoteException {
// TODO Auto-generated method stub
@@ -269,8 +276,15 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public Bitmap screenshotApplications(IBinder arg0, int displayId, int arg1,
- int arg2, boolean arg3) throws RemoteException {
+ public boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth,
+ int maxHeight) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@@ -293,7 +307,7 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
+ public void setAppTask(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
@@ -362,6 +376,10 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void setForcedDisplayScalingMode(int displayId, int mode) {
+ }
+
+ @Override
public void setInTouchMode(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 7a73fae..27b406a 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -21,9 +21,11 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.util.Xml;
import java.io.IOException;
@@ -36,9 +38,13 @@ import java.io.IOException;
*
*/
public class LayoutInflater_Delegate {
-
private static final String TAG_MERGE = "merge";
+ private static final String ATTR_LAYOUT = "layout";
+
+ private static final int[] ATTRS_THEME = new int[] {
+ com.android.internal.R.attr.theme };
+
public static boolean sIsInInclude = false;
/**
@@ -49,7 +55,7 @@ public class LayoutInflater_Delegate {
*/
@LayoutlibDelegate
/* package */ static void rInflate(LayoutInflater thisInflater, XmlPullParser parser,
- View parent, final AttributeSet attrs, boolean finishInflate, boolean inheritContext)
+ View parent, Context context, AttributeSet attrs, boolean finishInflate)
throws XmlPullParserException, IOException {
if (finishInflate == false) {
@@ -61,7 +67,7 @@ public class LayoutInflater_Delegate {
// ---- START DEFAULT IMPLEMENTATION.
- thisInflater.rInflate_Original(parser, parent, attrs, finishInflate, inheritContext);
+ thisInflater.rInflate_Original(parser, parent, context, attrs, finishInflate);
// ---- END DEFAULT IMPLEMENTATION.
@@ -74,15 +80,50 @@ public class LayoutInflater_Delegate {
}
@LayoutlibDelegate
- public static void parseInclude(LayoutInflater thisInflater, XmlPullParser parser, View parent,
- AttributeSet attrs, boolean inheritContext) throws XmlPullParserException, IOException {
-
+ public static void parseInclude(LayoutInflater thisInflater, XmlPullParser parser,
+ Context context, View parent, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
int type;
if (parent instanceof ViewGroup) {
- final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
+ // Apply a theme wrapper, if requested. This is sort of a weird
+ // edge case, since developers think the <include> overwrites
+ // values in the AttributeSet of the included View. So, if the
+ // included View has a theme attribute, we'll need to ignore it.
+ final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
+ final int themeResId = ta.getResourceId(0, 0);
+ final boolean hasThemeOverride = themeResId != 0;
+ if (hasThemeOverride) {
+ context = new ContextThemeWrapper(context, themeResId);
+ }
+ ta.recycle();
+
+ // If the layout is pointing to a theme attribute, we have to
+ // massage the value to get a resource identifier out of it.
+ int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
+ if (layout == 0) {
+ final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+ if (value == null || value.length() <= 0) {
+ throw new InflateException("You must specify a layout in the"
+ + " include tag: <include layout=\"@layout/layoutID\" />");
+ }
+
+ // Attempt to resolve the "?attr/name" string to an identifier.
+ layout = context.getResources().getIdentifier(value.substring(1), null, null);
+ }
+
+ // The layout might be referencing a theme attribute.
+ // ---- START CHANGES
+ if (layout != 0) {
+ final TypedValue tempValue = new TypedValue();
+ if (context.getTheme().resolveAttribute(layout, tempValue, true)) {
+ layout = tempValue.resourceId;
+ }
+ }
+ // ---- END CHANGES
+
if (layout == 0) {
- final String value = attrs.getAttributeValue(null, "layout");
+ final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
if (value == null) {
throw new InflateException("You must specifiy a layout in the"
+ " include tag: <include layout=\"@layout/layoutID\" />");
@@ -111,13 +152,20 @@ public class LayoutInflater_Delegate {
if (TAG_MERGE.equals(childName)) {
// Inflate all children.
- thisInflater.rInflate(childParser, parent, childAttrs, false,
- inheritContext);
+ thisInflater.rInflate(childParser, parent, context, childAttrs, false);
} else {
final View view = thisInflater.createViewFromTag(parent, childName,
- childAttrs, inheritContext);
+ context, childAttrs, hasThemeOverride);
final ViewGroup group = (ViewGroup) parent;
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.Include);
+ final int id = a.getResourceId(
+ com.android.internal.R.styleable.Include_id, View.NO_ID);
+ final int visibility = a.getInt(
+ com.android.internal.R.styleable.Include_visibility, -1);
+ a.recycle();
+
// We try to load the layout params set in the <include /> tag. If
// they don't exist, we will rely on the layout params set in the
// included XML file.
@@ -133,34 +181,20 @@ public class LayoutInflater_Delegate {
// ---- END CHANGES
params = group.generateLayoutParams(attrs);
-
- } catch (RuntimeException e) {
- // ---- START CHANGES
- sIsInInclude = false;
- // ---- END CHANGES
-
- params = group.generateLayoutParams(childAttrs);
+ } catch (RuntimeException ignored) {
+ // Ignore, just fail over to child attrs.
} finally {
// ---- START CHANGES
sIsInInclude = false;
// ---- END CHANGES
-
- if (params != null) {
- view.setLayoutParams(params);
- }
}
+ if (params == null) {
+ params = group.generateLayoutParams(childAttrs);
+ }
+ view.setLayoutParams(params);
// Inflate all children.
- thisInflater.rInflate(childParser, view, childAttrs, true, true);
-
- // Attempt to override the included layout's android:id with the
- // one set on the <include /> tag itself.
- TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.View, 0, 0);
- int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
- // While we're at it, let's try to override android:visibility.
- int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
- a.recycle();
+ thisInflater.rInflateChildren(childParser, view, childAttrs, true);
if (id != View.NO_ID) {
view.setId(id);
@@ -188,12 +222,6 @@ public class LayoutInflater_Delegate {
throw new InflateException("<include /> can only be used inside of a ViewGroup");
}
- final int currentDepth = parser.getDepth();
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
- // Empty
- }
+ LayoutInflater.consumeChildElements(parser);
}
-
-
}
diff --git a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
index 38846bd..a0db7bf 100644
--- a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
@@ -65,6 +65,9 @@ public class ShadowPainter {
@SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"}) // Imported code
public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
float shadowOpacity, int shadowRgb) {
+ if (shadowSize == 0) {
+ return source;
+ }
// This code is based on
// http://www.jroller.com/gfx/entry/non_rectangular_shadow
diff --git a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
index e72a0db..51d32e3 100644
--- a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
@@ -46,16 +46,12 @@ public class ViewGroup_Delegate {
/*package*/ static boolean drawChild(ViewGroup thisVG, Canvas canvas, View child,
long drawingTime) {
if (child.getZ() > thisVG.getZ()) {
+ // The background's bounds are set lazily. Make sure they are set correctly so that
+ // the outline obtained is correct.
+ child.setBackgroundBounds();
ViewOutlineProvider outlineProvider = child.getOutlineProvider();
- Outline outline = new Outline();
+ Outline outline = child.mAttachInfo.mTmpOutline;
outlineProvider.getOutline(child, outline);
- if (outline.mPath == null && outline.mRect == null) {
- // Sometimes, the bounds of the background drawable are not set until View.draw()
- // is called. So, we set the bounds manually and try to get the outline again.
- child.getBackground().setBounds(0, 0, child.mRight - child.mLeft,
- child.mBottom - child.mTop);
- outlineProvider.getOutline(child, outline);
- }
if (outline.mPath != null || (outline.mRect != null && !outline.mRect.isEmpty())) {
int restoreTo = transformCanvas(thisVG, canvas, child);
drawShadow(thisVG, canvas, child, outline);
diff --git a/tools/layoutlib/bridge/src/android/view/View_Delegate.java b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
index 8215f7c..408ec54 100644
--- a/tools/layoutlib/bridge/src/android/view/View_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
@@ -16,8 +16,12 @@
package android.view;
+import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import android.content.Context;
+import android.os.IBinder;
+
/**
* Delegate used to provide new implementation of a select few methods of {@link View}
*
@@ -31,4 +35,13 @@ public class View_Delegate {
/*package*/ static boolean isInEditMode(View thisView) {
return true;
}
+
+ @LayoutlibDelegate
+ /*package*/ static IBinder getWindowToken(View thisView) {
+ Context baseContext = BridgeContext.getBaseContext(thisView.getContext());
+ if (baseContext instanceof BridgeContext) {
+ return ((BridgeContext) baseContext).getBinder();
+ }
+ return null;
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index 78242a8..d691c8e 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -110,6 +110,11 @@ public class WindowCallback implements Window.Callback {
}
@Override
+ public boolean onSearchRequested(SearchEvent searchEvent) {
+ return onSearchRequested();
+ }
+
+ @Override
public boolean onSearchRequested() {
return false;
}
@@ -120,6 +125,11 @@ public class WindowCallback implements Window.Callback {
}
@Override
+ public ActionMode onWindowStartingActionMode(Callback callback, int type) {
+ return null;
+ }
+
+ @Override
public void onActionModeStarted(ActionMode mode) {
}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java b/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 6558b6a..0000000
--- a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.RenderAction;
-
-import android.content.Context;
-import android.view.BridgeInflater;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * Custom implementation of PolicyManager that does nothing to run in LayoutLib.
- *
- */
-public class PolicyManager {
-
- public static Window makeNewWindow(Context context) {
- // this will likely crash somewhere beyond so we log it.
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
- "Call to PolicyManager.makeNewWindow is not supported", null);
- return null;
- }
-
- public static LayoutInflater makeNewLayoutInflater(Context context) {
- return new BridgeInflater(context, RenderAction.getCurrentContext().getLayoutlibCallback());
- }
-
- public static WindowManagerPolicy makeNewWindowManager() {
- // this will likely crash somewhere beyond so we log it.
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
- "Call to PolicyManager.makeNewWindowManager is not supported", null);
- return null;
- }
-
- public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
- return new FallbackEventHandler() {
- @Override
- public void setView(View v) {
- }
-
- @Override
- public void preDispatchKeyEvent(KeyEvent event) {
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- return false;
- }
- };
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index c6d60f8..af67a43 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -16,9 +16,6 @@
package com.android.layoutlib.bridge;
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
-import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
-
import com.android.annotations.NonNull;
import com.android.ide.common.rendering.api.Capability;
import com.android.ide.common.rendering.api.DrawableParams;
@@ -36,13 +33,12 @@ import com.android.resources.ResourceType;
import com.android.tools.layoutlib.create.MethodAdapter;
import com.android.tools.layoutlib.create.OverrideMethod;
import com.android.util.Pair;
-import com.ibm.icu.util.ULocale;
-import libcore.io.MemoryMappedFile_Delegate;
import android.content.res.BridgeAssetManager;
import android.graphics.Bitmap;
import android.graphics.FontFamily_Delegate;
import android.graphics.Typeface_Delegate;
+import android.icu.util.ULocale;
import android.os.Looper;
import android.os.Looper_Accessor;
import android.view.View;
@@ -60,6 +56,11 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
+import libcore.io.MemoryMappedFile_Delegate;
+
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
+import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+
/**
* Main entry point of the LayoutLib Bridge.
* <p/>To use this bridge, simply instantiate an object of type {@link Bridge} and call
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java
index ea5f1ea..e589d9e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java
@@ -16,9 +16,9 @@
package com.android.layoutlib.bridge.android;
-import java.util.Locale;
+import android.icu.util.ULocale;
-import com.ibm.icu.util.ULocale;
+import java.util.Locale;
/**
* This class provides an alternate implementation for {@code java.util.Locale#toLanguageTag}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 2cbbeba..eded804 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -16,7 +16,6 @@
package com.android.layoutlib.bridge.android;
-import android.os.IBinder;
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.AssetRepository;
import com.android.ide.common.rendering.api.ILayoutPullParser;
@@ -65,8 +64,12 @@ import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
import android.os.Looper;
+import android.os.Parcel;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -74,6 +77,7 @@ import android.util.TypedValue;
import android.view.BridgeInflater;
import android.view.Display;
import android.view.DisplayAdjustments;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -81,6 +85,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.textservice.TextServicesManager;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -137,8 +142,10 @@ public final class BridgeContext extends Context {
private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
private SharedPreferences mSharedPreferences;
+ private ClassLoader mClassLoader;
+ private IBinder mBinder;
- /**
+ /**
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
* @param metrics the {@link DisplayMetrics}.
* @param renderResources the configured resources (both framework and projects) for this
@@ -461,7 +468,21 @@ public final class BridgeContext extends Context {
@Override
public ClassLoader getClassLoader() {
- return this.getClass().getClassLoader();
+ if (mClassLoader == null) {
+ mClassLoader = new ClassLoader(getClass().getClassLoader()) {
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ for (String prefix : BridgeInflater.getClassPrefixList()) {
+ if (name.startsWith(prefix)) {
+ // These are framework classes and should not be loaded from the app.
+ throw new ClassNotFoundException(name + " not found");
+ }
+ }
+ return BridgeContext.this.mLayoutlibCallback.findClass(name);
+ }
+ };
+ }
+ return mClassLoader;
}
@Override
@@ -499,6 +520,34 @@ public final class BridgeContext extends Context {
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
+ @Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ if (serviceClass.equals(LayoutInflater.class)) {
+ return LAYOUT_INFLATER_SERVICE;
+ }
+
+ if (serviceClass.equals(TextServicesManager.class)) {
+ return TEXT_SERVICES_MANAGER_SERVICE;
+ }
+
+ if (serviceClass.equals(WindowManager.class)) {
+ return WINDOW_SERVICE;
+ }
+
+ if (serviceClass.equals(PowerManager.class)) {
+ return POWER_SERVICE;
+ }
+
+ if (serviceClass.equals(DisplayManager.class)) {
+ return DISPLAY_SERVICE;
+ }
+
+ if (serviceClass.equals(AccessibilityManager.class)) {
+ return ACCESSIBILITY_SERVICE;
+ }
+
+ throw new UnsupportedOperationException("Unsupported Service: " + serviceClass);
+ }
@Override
public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {
@@ -664,44 +713,48 @@ public final class BridgeContext extends Context {
}
}
} else if (defStyleRes != 0) {
- boolean isFrameworkRes = true;
- Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
- if (value == null) {
- value = mLayoutlibCallback.resolveResourceId(defStyleRes);
- isFrameworkRes = false;
- }
+ StyleResourceValue item = mDynamicIdToStyleMap.get(defStyleRes);
+ if (item != null) {
+ defStyleValues = item;
+ } else {
+ boolean isFrameworkRes = true;
+ Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
+ if (value == null) {
+ value = mLayoutlibCallback.resolveResourceId(defStyleRes);
+ isFrameworkRes = false;
+ }
- if (value != null) {
- if ((value.getFirst() == ResourceType.STYLE)) {
- // look for the style in all resources:
- StyleResourceValue item = mRenderResources.getStyle(value.getSecond(),
- isFrameworkRes);
- if (item != null) {
- if (defaultPropMap != null) {
- defaultPropMap.put("style", item.getName());
+ if (value != null) {
+ if ((value.getFirst() == ResourceType.STYLE)) {
+ // look for the style in all resources:
+ item = mRenderResources.getStyle(value.getSecond(), isFrameworkRes);
+ if (item != null) {
+ if (defaultPropMap != null) {
+ defaultPropMap.put("style", item.getName());
+ }
+
+ defStyleValues = item;
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Style with id 0x%x (resolved to '%s') does not exist.",
+ defStyleRes, value.getSecond()),
+ null);
}
-
- defStyleValues = item;
} else {
Bridge.getLog().error(null,
String.format(
- "Style with id 0x%x (resolved to '%s') does not exist.",
- defStyleRes, value.getSecond()),
+ "Resource id 0x%x is not of type STYLE (instead %s)",
+ defStyleRes, value.getFirst().toString()),
null);
}
} else {
Bridge.getLog().error(null,
String.format(
- "Resource id 0x%x is not of type STYLE (instead %s)",
- defStyleRes, value.getFirst().toString()),
+ "Failed to find style with id 0x%x in current theme",
+ defStyleRes),
null);
}
- } else {
- Bridge.getLog().error(null,
- String.format(
- "Failed to find style with id 0x%x in current theme",
- defStyleRes),
- null);
}
}
@@ -952,6 +1005,61 @@ public final class BridgeContext extends Context {
return context;
}
+ public IBinder getBinder() {
+ if (mBinder == null) {
+ // create a dummy binder. We only need it be not null.
+ mBinder = new IBinder() {
+ @Override
+ public String getInterfaceDescriptor() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public boolean pingBinder() {
+ return false;
+ }
+
+ @Override
+ public boolean isBinderAlive() {
+ return false;
+ }
+
+ @Override
+ public IInterface queryLocalInterface(String descriptor) {
+ return null;
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, String[] args) throws RemoteException {
+
+ }
+
+ @Override
+ public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
+
+ }
+
+ @Override
+ public boolean transact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ return false;
+ }
+
+ @Override
+ public void linkToDeath(DeathRecipient recipient, int flags)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
+ return false;
+ }
+ };
+ }
+ return mBinder;
+ }
+
//------------ NOT OVERRIDEN --------------------
@Override
@@ -991,6 +1099,12 @@ public final class BridgeContext extends Context {
}
@Override
+ public int checkSelfPermission(String arg0) {
+ // pass
+ return 0;
+ }
+
+ @Override
public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) {
// pass
return 0;
@@ -1370,6 +1484,11 @@ public final class BridgeContext extends Context {
// pass
}
+ public void sendBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp) {
+ // pass
+ }
+
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index c44a57c..8899e53 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -164,7 +164,8 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
}
@Override
- public void showInputMethodPickerFromClient(IInputMethodClient arg0) throws RemoteException {
+ public void showInputMethodPickerFromClient(IInputMethodClient arg0,
+ int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 9b755cd..085df85 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -147,6 +147,11 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
+ public boolean isDeviceIdleMode() throws RemoteException {
+ return false;
+ }
+
+ @Override
public boolean isScreenBrightnessBoosted() throws RemoteException {
return false;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index fb5d44f..771c3c8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -91,7 +91,11 @@ public final class BridgeWindow implements IWindow {
}
@Override
- public void doneAnimating() {
+ public void onAnimationStarted(int remainingFrameCount) {
+ }
+
+ @Override
+ public void onAnimationStopped() {
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 25f7078..4289689 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -191,12 +191,6 @@ public final class BridgeWindowSession implements IWindowSession {
}
@Override
- public void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
- float dsdx, float dtdx, float dsdy, float dtdy) {
- // pass for now.
- }
-
- @Override
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 04aadff..dcf82a3 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -24,6 +24,7 @@ import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -32,6 +33,17 @@ public class NavigationBar extends CustomBar {
/** Navigation bar background color attribute name. */
private static final String ATTR_COLOR = "navigationBarColor";
+ // These correspond to @dimen/navigation_side_padding in the system ui code.
+ private static final int PADDING_WIDTH_DEFAULT = 36;
+ private static final int PADDING_WIDTH_SW360 = 40;
+ private static final int PADDING_WIDTH_SW400 = 50;
+ // These corresponds to @dimen/navigation_key_width in the system ui code.
+ private static final int WIDTH_DEFAULT = 36;
+ private static final int WIDTH_SW360 = 40;
+ private static final int WIDTH_SW600 = 48;
+ private static final String LAYOUT_XML = "/bars/navigation_bar.xml";
+ private static final String LAYOUT_600DP_XML = "/bars/navigation_bar600dp.xml";
+
/**
* Constructor to be used when creating the {@link NavigationBar} as a regular control.
@@ -45,13 +57,13 @@ public class NavigationBar extends CustomBar {
((BridgeContext) context).getConfiguration().getLayoutDirection() ==
View.LAYOUT_DIRECTION_RTL,
(context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
- context.getApplicationInfo().targetSdkVersion);
+ 0);
}
public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
boolean rtlEnabled, int simulatedPlatformVersion) throws XmlPullParserException {
- super(context, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml",
- simulatedPlatformVersion);
+ super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
+ "navigation_bar.xml", simulatedPlatformVersion);
int color = getThemeAttrColor(ATTR_COLOR, true);
setBackgroundColor(color == 0 ? 0xFF000000 : color);
@@ -61,19 +73,76 @@ public class NavigationBar extends CustomBar {
// We do know the order though.
// 0 is a spacer.
int back = 1;
- int recent = 3;
+ int recent = 5;
if (orientation == LinearLayout.VERTICAL || (isRtl && !rtlEnabled)) {
// If RTL is enabled, then layoutlib mirrors the layout for us.
- back = 3;
+ back = 5;
recent = 1;
}
//noinspection SpellCheckingInspection
- loadIcon(back, "ic_sysbar_back.png", density, isRtl);
+ loadIcon(back, "ic_sysbar_back.png", density, isRtl);
//noinspection SpellCheckingInspection
- loadIcon(2, "ic_sysbar_home.png", density, isRtl);
+ loadIcon(3, "ic_sysbar_home.png", density, isRtl);
//noinspection SpellCheckingInspection
loadIcon(recent, "ic_sysbar_recent.png", density, isRtl);
+ setupNavBar(context, orientation);
+ }
+
+ private void setupNavBar(BridgeContext context, int orientation) {
+ float sw = getShortestWidth(context);
+ View leftPadding = getChildAt(0);
+ View rightPadding = getChildAt(6);
+ setSize(context, leftPadding, orientation, getSidePadding(sw));
+ setSize(context, rightPadding, orientation, getSidePadding(sw));
+ int navButtonWidth = getWidth(sw);
+ for (int i = 1; i < 6; i += 2) {
+ View navButton = getChildAt(i);
+ setSize(context, navButton, orientation, navButtonWidth);
+ }
+ if (sw >= 600) {
+ setSize(context, getChildAt(2), orientation, 128);
+ setSize(context, getChildAt(4), orientation, 128);
+ }
+ }
+
+ private static void setSize(BridgeContext context, View view, int orientation, int size) {
+ size *= context.getMetrics().density;
+ LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
+ if (orientation == HORIZONTAL) {
+ layoutParams.width = size;
+ } else {
+ layoutParams.height = size;
+ }
+ view.setLayoutParams(layoutParams);
+ }
+
+ private static int getSidePadding(float sw) {
+ if (sw >= 400) {
+ return PADDING_WIDTH_SW400;
+ }
+ if (sw >= 360) {
+ return PADDING_WIDTH_SW360;
+ }
+ return PADDING_WIDTH_DEFAULT;
+ }
+
+ private static int getWidth(float sw) {
+ if (sw >= 600) {
+ return WIDTH_SW600;
+ }
+ if (sw >= 360) {
+ return WIDTH_SW360;
+ }
+ return WIDTH_DEFAULT;
+ }
+
+ private static float getShortestWidth(BridgeContext context) {
+ DisplayMetrics metrics = context.getMetrics();
+ float sw = metrics.widthPixels < metrics.heightPixels ?
+ metrics.widthPixels : metrics.heightPixels;
+ sw /= metrics.density;
+ return sw;
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index 261cc98..dbee9ea 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.impl;
+import com.android.annotations.Nullable;
import com.android.layoutlib.bridge.util.Debug;
import com.android.layoutlib.bridge.util.SparseWeakArray;
@@ -48,7 +49,7 @@ import java.util.List;
* int -> Delegate class link.
*
* Native methods usually always have the int as parameters. The first thing the delegate method
- * will do is call {@link #getDelegate(int)} to get the Java object matching the int.
+ * will do is call {@link #getDelegate(long)} to get the Java object matching the int.
*
* Typical native init methods are returning a new int back to the Java class, so
* {@link #addNewDelegate(Object)} does the same.
@@ -57,7 +58,7 @@ import java.util.List;
* the Java object needs to count as a reference (even though it only holds an int), we use the
* following mechanism:
*
- * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(int)} adds and removes
+ * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(long)} adds and removes
* the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming
* the delegate.
*
@@ -70,12 +71,13 @@ import java.util.List;
* @param <T> the delegate class to manage
*/
public final class DelegateManager<T> {
+ @SuppressWarnings("FieldCanBeLocal")
private final Class<T> mClass;
private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>();
/** list used to store delegates when their main object holds a reference to them.
* This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
* @see #addNewDelegate(Object)
- * @see #removeJavaReferenceFor(int)
+ * @see #removeJavaReferenceFor(long)
*/
private final List<T> mJavaReferences = new ArrayList<T>();
private int mDelegateCounter = 0;
@@ -94,6 +96,7 @@ public final class DelegateManager<T> {
* @param native_object the native int.
* @return the delegate or null if not found.
*/
+ @Nullable
public T getDelegate(long native_object) {
if (native_object > 0) {
T delegate = mDelegates.get(native_object);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
index 803849f..646f960 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -17,7 +17,9 @@
package com.android.layoutlib.bridge.impl;
-import org.kxml2.io.KXmlParser;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -35,24 +37,36 @@ import java.io.InputStream;
*/
public class ParserFactory {
+ public final static boolean LOG_PARSER = false;
+
private final static String ENCODING = "UTF-8"; //$NON-NLS-1$
- public final static boolean LOG_PARSER = false;
+ // Used to get a new XmlPullParser from the client.
+ @Nullable
+ private static com.android.ide.common.rendering.api.ParserFactory sParserFactory;
- public static XmlPullParser create(File f)
+ public static void setParserFactory(
+ @Nullable com.android.ide.common.rendering.api.ParserFactory parserFactory) {
+ sParserFactory = parserFactory;
+ }
+
+ @NonNull
+ public static XmlPullParser create(@NonNull File f)
throws XmlPullParserException, FileNotFoundException {
InputStream stream = new FileInputStream(f);
return create(stream, f.getName(), f.length());
}
- public static XmlPullParser create(InputStream stream, String name)
+ @NonNull
+ public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
throws XmlPullParserException {
return create(stream, name, -1);
}
- private static XmlPullParser create(InputStream stream, String name, long size)
- throws XmlPullParserException {
- KXmlParser parser = instantiateParser(name);
+ @NonNull
+ private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name,
+ long size) throws XmlPullParserException {
+ XmlPullParser parser = instantiateParser(name);
stream = readAndClose(stream, name, size);
@@ -60,19 +74,20 @@ public class ParserFactory {
return parser;
}
- private static KXmlParser instantiateParser(String name) throws XmlPullParserException {
- KXmlParser parser;
- if (name != null) {
- parser = new CustomParser(name);
- } else {
- parser = new KXmlParser();
+ @NonNull
+ public static XmlPullParser instantiateParser(@Nullable String name)
+ throws XmlPullParserException {
+ if (sParserFactory == null) {
+ throw new XmlPullParserException("ParserFactory not initialized.");
}
+ XmlPullParser parser = sParserFactory.createParser(name);
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
return parser;
}
- private static InputStream readAndClose(InputStream stream, String name, long size)
- throws XmlPullParserException {
+ @NonNull
+ private static InputStream readAndClose(@NonNull InputStream stream, @Nullable String name,
+ long size) throws XmlPullParserException {
// just a sanity check. It's doubtful we'll have such big files!
if (size > Integer.MAX_VALUE) {
throw new XmlPullParserException("File " + name + " is too big to be parsed");
@@ -121,22 +136,8 @@ public class ParserFactory {
} finally {
try {
bufferedStream.close();
- } catch (IOException e) {
+ } catch (IOException ignored) {
}
}
}
-
- private static class CustomParser extends KXmlParser {
- private final String mName;
-
- CustomParser(String name) {
- super();
- mName = name;
- }
-
- @Override
- public String toString() {
- return mName;
- }
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index c708316..f3a0d58 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -99,6 +99,9 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
return result;
}
+ // setup the ParserFactory
+ ParserFactory.setParserFactory(mParams.getLayoutlibCallback().getParserFactory());
+
HardwareConfig hardwareConfig = mParams.getHardwareConfig();
// setup the display Metrics.
@@ -271,7 +274,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
mContext.getRenderResources().setFrameworkResourceIdProvider(null);
mContext.getRenderResources().setLogger(null);
}
-
+ ParserFactory.setParserFactory(null);
}
public static BridgeContext getCurrentContext() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 9e26502..26f9000 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -38,6 +38,9 @@ import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 677c744..a3fde866 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.impl;
+import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
import com.android.ide.common.rendering.api.LayoutLog;
@@ -70,6 +71,10 @@ public final class ResourceHelper {
public static int getColor(String value) {
if (value != null) {
if (!value.startsWith("#")) {
+ if (value.startsWith(SdkConstants.PREFIX_THEME_REF)) {
+ throw new NumberFormatException(String.format(
+ "Attribute '%s' not found. Are you using the right theme?", value));
+ }
throw new NumberFormatException(
String.format("Color value '%s' must start with #", value));
}
diff --git a/tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java
deleted file mode 100644
index d94c205..0000000
--- a/tools/layoutlib/bridge/src/libcore/icu/DateIntervalFormat_Delegate.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 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 libcore.icu;
-
-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;
-import com.ibm.icu.util.ULocale;
-
-public class DateIntervalFormat_Delegate {
-
- // ---- delegate manager ----
- private static final DelegateManager<DateIntervalFormat_Delegate> sManager =
- new DelegateManager<DateIntervalFormat_Delegate>(DateIntervalFormat_Delegate.class);
-
- // ---- delegate data ----
- private DateIntervalFormat mFormat;
-
-
- // ---- native methods ----
-
- @LayoutlibDelegate
- /*package*/static String formatDateInterval(long address, long fromDate, long toDate) {
- DateIntervalFormat_Delegate delegate = sManager.getDelegate((int)address);
- if (delegate == null) {
- Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Unable for find native DateIntervalFormat", null);
- return null;
- }
- DateInterval interval = new DateInterval(fromDate, toDate);
- StringBuffer sb = new StringBuffer();
- FieldPosition pos = new FieldPosition(0);
- delegate.mFormat.format(interval, sb, pos);
- return sb.toString();
- }
-
- @LayoutlibDelegate
- /*package*/ static long createDateIntervalFormat(String skeleton, String localeName,
- String tzName) {
- TimeZone prevDefaultTz = TimeZone.getDefault();
- TimeZone.setDefault(TimeZone.getTimeZone(tzName));
- DateIntervalFormat_Delegate newDelegate = new DateIntervalFormat_Delegate();
- newDelegate.mFormat =
- DateIntervalFormat.getInstance(skeleton, new ULocale(localeName));
- TimeZone.setDefault(prevDefaultTz);
- 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 b8b5fed..9c58010 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -17,9 +17,11 @@
package libcore.icu;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-import com.ibm.icu.text.DateTimePatternGenerator;
-import com.ibm.icu.util.Currency;
-import com.ibm.icu.util.ULocale;
+
+import android.icu.text.DateTimePatternGenerator;
+import android.icu.util.Currency;
+import android.icu.util.ULocale;
+import android.icu.util.VersionInfo;
import java.util.Locale;
@@ -53,18 +55,19 @@ public class ICU_Delegate {
}
@LayoutlibDelegate
+ @SuppressWarnings("deprecation")
/*package*/ static String getCldrVersion() {
- return "22.1.1"; // TODO: check what the right value should be.
+ return VersionInfo.ICU_DATA_VERSION.toString();
}
@LayoutlibDelegate
/*package*/ static String getIcuVersion() {
- return "unknown_layoutlib";
+ return VersionInfo.ICU_VERSION.toString();
}
@LayoutlibDelegate
/*package*/ static String getUnicodeVersion() {
- return "5.2";
+ return VersionInfo.UNICODE_7_0.toString();
}
@LayoutlibDelegate
@@ -181,8 +184,8 @@ public class ICU_Delegate {
/*package*/ static boolean initLocaleDataNative(String locale, LocaleData result) {
// Used by Calendar.
- result.firstDayOfWeek = Integer.valueOf(1);
- result.minimalDaysInFirstWeek = Integer.valueOf(1);
+ result.firstDayOfWeek = 1;
+ result.minimalDaysInFirstWeek = 1;
// Used by DateFormatSymbols.
result.amPm = new String[] { "AM", "PM" };
@@ -252,4 +255,9 @@ public class ICU_Delegate {
/*package*/ static String getDefaultLocale() {
return ICU.getDefaultLocale();
}
+
+ @LayoutlibDelegate
+ /*package*/ static String getTZDataVersion() {
+ return ICU.getTZDataVersion();
+ }
}