diff options
author | Xavier Ducrohet <xav@android.com> | 2010-11-22 20:09:55 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-11-23 11:54:25 -0800 |
commit | 2d56b273ef6e2984a4e8914fb67772b173d0a154 (patch) | |
tree | a27ae6be789d770986d019795807dfa8df0455a5 /tools/layoutlib | |
parent | b43d7589cf6201fc05f4c9d8b4a0c44d7cdba81e (diff) | |
download | frameworks_base-2d56b273ef6e2984a4e8914fb67772b173d0a154.zip frameworks_base-2d56b273ef6e2984a4e8914fb67772b173d0a154.tar.gz frameworks_base-2d56b273ef6e2984a4e8914fb67772b173d0a154.tar.bz2 |
Layoutlib: use default nine patch classes.
Move away from using our own implementation of NinePatchDrawable.
Now use native delegate for a few methods of NinePatch.
The byte[] used to describe the 9-patch chunk is entirely controlled
by the delegate. Therefore, while the default version (JNI) use the
array as a representation of a C struct, this version uses the array
as a serialized version of NinePatchChunk.
A cache mechanism using SoftReferences allows us to not deserialize
the array every time rendering needs to access the chunk itself.
The Bridge-level cache mechanism for bitmaps and nine-patches as
changed. Since the new nine-patches doesn't hold the bitmap
data anymore (it's stored in a normal Android bitmap which
is cached itself through the cache), then the nine-patch cache
has been changed to only contain the nine patch chunk.
Also initialize the canvas with the display metrics to prepare
for correct scaling when density of the assets don't match the target
density.
Still to come: actual density support in the 9-patch drawing code.
Change-Id: Ibefcccf4432e1986e8436e0c41a0107741593536
Diffstat (limited to 'tools/layoutlib')
10 files changed, 330 insertions, 166 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java index 6fd59c4..212223c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java +++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java @@ -456,7 +456,11 @@ public class BitmapFactory { // into is.read(...) This number is not related to the value passed // to mark(...) above. try { - bm = Bitmap_Delegate.createBitmap(is, Density.MEDIUM); + Density density = Density.MEDIUM; + if (opts != null) { + density = Density.getEnum(opts.inDensity); + } + bm = Bitmap_Delegate.createBitmap(is, true, density); } catch (IOException e) { return null; } diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index 0920497..b4c51b2 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -75,32 +75,56 @@ public class Bitmap_Delegate { /** * Creates and returns a {@link Bitmap} initialized with the given file content. + * + * @param input the file from which to read the bitmap content + * @param isMutable whether the bitmap is mutable + * @param density the density associated with the bitmap + * + * @see Bitmap#isMutable() + * @see Bitmap#getDensity() */ - public static Bitmap createBitmap(File input, Density density) throws IOException { + public static Bitmap createBitmap(File input, boolean isMutable, Density density) + throws IOException { // create a delegate with the content of the file. Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input)); - return createBitmap(delegate, density.getValue()); + return createBitmap(delegate, isMutable, density.getValue()); } /** * Creates and returns a {@link Bitmap} initialized with the given stream content. + * + * @param input the stream from which to read the bitmap content + * @param isMutable whether the bitmap is mutable + * @param density the density associated with the bitmap + * + * @see Bitmap#isMutable() + * @see Bitmap#getDensity() */ - public static Bitmap createBitmap(InputStream input, Density density) throws IOException { + public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density) + throws IOException { // create a delegate with the content of the stream. Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input)); - return createBitmap(delegate, density.getValue()); + return createBitmap(delegate, isMutable, density.getValue()); } /** * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage} + * + * @param image the bitmap content + * @param isMutable whether the bitmap is mutable + * @param density the density associated with the bitmap + * + * @see Bitmap#isMutable() + * @see Bitmap#getDensity() */ - public static Bitmap createBitmap(BufferedImage image, Density density) throws IOException { + public static Bitmap createBitmap(BufferedImage image, boolean isMutable, Density density) + throws IOException { // create a delegate with the given image. Bitmap_Delegate delegate = new Bitmap_Delegate(image); - return createBitmap(delegate, density.getValue()); + return createBitmap(delegate, isMutable, density.getValue()); } /** @@ -153,7 +177,7 @@ public class Bitmap_Delegate { // create a delegate with the content of the stream. Bitmap_Delegate delegate = new Bitmap_Delegate(image); - return createBitmap(delegate, Bitmap.getDefaultDensity()); + return createBitmap(delegate, mutable, Bitmap.getDefaultDensity()); } /*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) { @@ -166,8 +190,7 @@ public class Bitmap_Delegate { } /*package*/ static void nativeRecycle(int nativeBitmap) { - // FIXME implement native delegate - throw new UnsupportedOperationException("Native delegate needed for Bitmap"); + sManager.removeDelegate(nativeBitmap); } /*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality, @@ -336,11 +359,11 @@ public class Bitmap_Delegate { mImage = image; } - private static Bitmap createBitmap(Bitmap_Delegate delegate, int density) { + private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) { // get its native_int int nativeInt = sManager.addDelegate(delegate); // and create/return a new Bitmap with it - return new Bitmap(nativeInt, true /*isMutable*/, null /*ninePatchChunk*/, density); + return new Bitmap(nativeInt, isMutable, null /*ninePatchChunk*/, density); } } diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index cea07af..08f3c7a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -960,7 +960,7 @@ public class Canvas_Delegate { * Creates a new {@link Graphics2D} based on the {@link Paint} parameters. * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used. */ - private Graphics2D getCustomGraphics(Paint_Delegate paint) { + /*package*/ Graphics2D getCustomGraphics(Paint_Delegate paint) { // make new one Graphics2D g = getGraphics2d(); g = (Graphics2D)g.create(); diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java new file mode 100644 index 0000000..3d26e47 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2010 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.graphics; + +import com.android.layoutlib.bridge.impl.DelegateManager; +import com.android.ninepatch.NinePatchChunk; + +import android.graphics.drawable.NinePatchDrawable; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Map; + +/** + * Delegate implementing the native methods of android.graphics.NinePatch + * + * Through the layoutlib_create tool, the original native methods of NinePatch have been replaced + * by calls to methods of the same name in this delegate class. + * + * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager} + * around to map int to instance of the delegate. + * + */ +public class NinePatch_Delegate { + + /** + * Cache map for {@link NinePatchChunk}. + * When the chunks are created they are serialized into a byte[], and both are put + * in the cache, using a {@link SoftReference} for the chunk. The default Java classes + * for {@link NinePatch} and {@link NinePatchDrawable} only reference to the byte[] data, and + * provide this for drawing. + * Using the cache map allows us to not have to deserialize the byte[] back into a + * {@link NinePatchChunk} every time a rendering is done. + */ + private final static Map<byte[], SoftReference<NinePatchChunk>> sChunkCache = + new HashMap<byte[], SoftReference<NinePatchChunk>>(); + + // ---- Public Helper methods ---- + + /** + * Serializes the given chunk. + * + * @return the serialized data for the chunk. + */ + public static byte[] serialize(NinePatchChunk chunk) { + // serialize the chunk to get a byte[] + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = null; + try { + oos = new ObjectOutputStream(baos); + oos.writeObject(chunk); + } catch (IOException e) { + //FIXME log this. + return null; + } finally { + if (oos != null) { + try { + oos.close(); + } catch (IOException e) { + } + } + } + + // get the array and add it to the cache + byte[] array = baos.toByteArray(); + sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk)); + return array; + } + + // ---- native methods ---- + + /*package*/ static boolean isNinePatchChunk(byte[] chunk) { + NinePatchChunk chunkObject = getChunk(chunk); + if (chunkObject != null) { + return true; + } + + return false; + } + + /*package*/ static void validateNinePatchChunk(int bitmap, 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. + } + + /*package*/ static void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance, + byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) { + draw(canvas_instance, + (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(), + bitmap_instance, c, paint_instance_or_null, + destDensity, srcDensity); + } + + /*package*/ static void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance, + byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) { + draw(canvas_instance, + loc.left, loc.top, loc.width(), loc.height(), + bitmap_instance, c, paint_instance_or_null, + destDensity, srcDensity); + } + + private static void draw(int canvas_instance, + int left, int top, int right, int bottom, + int bitmap_instance, byte[] c, int paint_instance_or_null, + int destDensity, int srcDensity) { + // get the delegate from the native int. + Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance); + if (bitmap_delegate == null) { + assert false; + return; + } + + if (c == null) { + // not a 9-patch? + BufferedImage image = bitmap_delegate.getImage(); + Canvas_Delegate.native_drawBitmap(canvas_instance, bitmap_instance, + new Rect(0, 0, image.getWidth(), image.getHeight()), + new Rect(left, top, right, bottom), + paint_instance_or_null, destDensity, srcDensity); + return; + } + + NinePatchChunk chunkObject = getChunk(c); + assert chunkObject != null; + if (chunkObject == null) { + return; + } + + Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance); + if (canvas_delegate == null) { + assert false; + return; + } + + // this one can be null + Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null); + + Graphics2D graphics; + if (paint_delegate != null) { + graphics = canvas_delegate.getCustomGraphics(paint_delegate); + } else { + graphics = canvas_delegate.getGraphics2d(); + } + + try { + chunkObject.draw(bitmap_delegate.getImage(), graphics, + left, top, right - left, bottom - top); + } finally { + if (paint_delegate != null) { + graphics.dispose(); + } + } + + } + + /*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) { + return 0; + } + + // ---- Private Helper methods ---- + + /** + * Returns a {@link NinePatchChunk} object for the given serialized representation. + * + * If the chunk is present in the cache then the object from the cache is returned, otherwise + * the array is deserialized into a {@link NinePatchChunk} object. + * + * @param array the serialized representation of the chunk. + * @return the NinePatchChunk or null if deserialization failed. + */ + private static NinePatchChunk getChunk(byte[] array) { + SoftReference<NinePatchChunk> chunkRef = sChunkCache.get(array); + NinePatchChunk chunk = chunkRef.get(); + if (chunk == null) { + ByteArrayInputStream bais = new ByteArrayInputStream(array); + ObjectInputStream ois = null; + try { + ois = new ObjectInputStream(bais); + chunk = (NinePatchChunk) ois.readObject(); + + // put back the chunk in the cache + if (chunk != null) { + sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk)); + } + } catch (IOException e) { + // FIXME: log this + return null; + } catch (ClassNotFoundException e) { + // FIXME: log this + return null; + } finally { + if (ois != null) { + try { + ois.close(); + } catch (IOException e) { + } + } + } + } + + return chunk; + } +} 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 e691fdf..35ba73d 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -26,7 +26,7 @@ import com.android.layoutlib.api.SceneResult; import com.android.layoutlib.bridge.android.BridgeAssetManager; import com.android.layoutlib.bridge.impl.FontLoader; import com.android.layoutlib.bridge.impl.LayoutSceneImpl; -import com.android.ninepatch.NinePatch; +import com.android.ninepatch.NinePatchChunk; import com.android.tools.layoutlib.create.MethodAdapter; import com.android.tools.layoutlib.create.OverrideMethod; @@ -73,13 +73,13 @@ public final class Bridge extends LayoutBridge { private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache = new HashMap<Object, Map<String, SoftReference<Bitmap>>>(); - private final static Map<Object, Map<String, SoftReference<NinePatch>>> sProject9PatchCache = - new HashMap<Object, Map<String, SoftReference<NinePatch>>>(); + private final static Map<Object, Map<String, SoftReference<NinePatchChunk>>> sProject9PatchCache = + new HashMap<Object, Map<String, SoftReference<NinePatchChunk>>>(); private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache = new HashMap<String, SoftReference<Bitmap>>(); - private final static Map<String, SoftReference<NinePatch>> sFramework9PatchCache = - new HashMap<String, SoftReference<NinePatch>>(); + private final static Map<String, SoftReference<NinePatchChunk>> sFramework9PatchCache = + new HashMap<String, SoftReference<NinePatchChunk>>(); private static Map<String, Map<String, Integer>> sEnumValueMap; @@ -252,23 +252,23 @@ public final class Bridge extends LayoutBridge { } /** - * Sets a 9 patch in a project cache or in the framework cache. + * Sets a 9 patch chunk in a project cache or in the framework cache. * @param value the path of the 9 patch * @param ninePatch the 9 patch object * @param projectKey the key of the project, or null to put the bitmap in the framework cache. */ - public static void setCached9Patch(String value, NinePatch ninePatch, Object projectKey) { + public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) { if (projectKey != null) { - Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey); + Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey); if (map == null) { - map = new HashMap<String, SoftReference<NinePatch>>(); + map = new HashMap<String, SoftReference<NinePatchChunk>>(); sProject9PatchCache.put(projectKey, map); } - map.put(value, new SoftReference<NinePatch>(ninePatch)); + map.put(value, new SoftReference<NinePatchChunk>(ninePatch)); } else { - sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch)); + sFramework9PatchCache.put(value, new SoftReference<NinePatchChunk>(ninePatch)); } } @@ -436,24 +436,24 @@ public final class Bridge extends LayoutBridge { } /** - * Returns the 9 patch for a specific path, from a specific project cache, or from the + * Returns the 9 patch chunk for a specific path, from a specific project cache, or from the * framework cache. * @param value the path of the 9 patch * @param projectKey the key of the project, or null to query the framework cache. * @return the cached 9 patch or null if not found. */ - public static NinePatch getCached9Patch(String value, Object projectKey) { + public static NinePatchChunk getCached9Patch(String value, Object projectKey) { if (projectKey != null) { - Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey); + Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey); if (map != null) { - SoftReference<NinePatch> ref = map.get(value); + SoftReference<NinePatchChunk> ref = map.get(value); if (ref != null) { return ref.get(); } } } else { - SoftReference<NinePatch> ref = sFramework9PatchCache.get(value); + SoftReference<NinePatchChunk> ref = sFramework9PatchCache.get(value); if (ref != null) { return ref.get(); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/NinePatchDrawable.java deleted file mode 100644 index 4efa631..0000000 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/NinePatchDrawable.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.layoutlib.bridge.android; - -import com.android.ninepatch.NinePatch; - -import android.graphics.Canvas; -import android.graphics.Canvas_Delegate; -import android.graphics.ColorFilter; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -public class NinePatchDrawable extends Drawable { - - private NinePatch m9Patch; - - public NinePatchDrawable(NinePatch ninePatch) { - m9Patch = ninePatch; - } - - @Override - public int getMinimumWidth() { - return m9Patch.getWidth(); - } - - @Override - public int getMinimumHeight() { - return m9Patch.getHeight(); - } - - /** - * Return the intrinsic width of the underlying drawable object. Returns - * -1 if it has no intrinsic width, such as with a solid color. - */ - @Override - public int getIntrinsicWidth() { - return m9Patch.getWidth(); - } - - /** - * Return the intrinsic height of the underlying drawable object. Returns - * -1 if it has no intrinsic height, such as with a solid color. - */ - @Override - public int getIntrinsicHeight() { - return m9Patch.getHeight(); - } - - /** - * Return in padding the insets suggested by this Drawable for placing - * content inside the drawable's bounds. Positive values move toward the - * center of the Drawable (set Rect.inset). Returns true if this drawable - * actually has a padding, else false. When false is returned, the padding - * is always set to 0. - */ - @Override - public boolean getPadding(Rect padding) { - int[] padd = new int[4]; - m9Patch.getPadding(padd); - padding.left = padd[0]; - padding.top = padd[1]; - padding.right = padd[2]; - padding.bottom = padd[3]; - return true; - } - - @Override - public void draw(Canvas canvas) { - Rect r = getBounds(); - Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); - m9Patch.draw(canvasDelegate.getGraphics2d(), r.left, r.top, r.width(), r.height()); - - return; - } - - - // ----------- Not implemented methods --------------- - - - @Override - public int getOpacity() { - // FIXME - return 0xFF; - } - - @Override - public void setAlpha(int arg0) { - // FIXME ! - } - - @Override - public void setColorFilter(ColorFilter arg0) { - // FIXME - } -} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java index 2e3f9a8..f7d249e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java @@ -313,10 +313,12 @@ public class LayoutSceneImpl { // create an Android bitmap around the BufferedImage Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage, + true /*isMutable*/, Density.getEnum(mParams.getDensity())); // create a Canvas around the Android bitmap Canvas canvas = new Canvas(bitmap); + canvas.setDensity(mParams.getDensity()); // to set the logger, get the native delegate Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); 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 3e506b8..ceb8a0d 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 @@ -22,8 +22,8 @@ import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; -import com.android.layoutlib.bridge.android.NinePatchDrawable; import com.android.ninepatch.NinePatch; +import com.android.ninepatch.NinePatchChunk; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParser; @@ -31,9 +31,12 @@ import org.xmlpull.v1.XmlPullParserException; import android.graphics.Bitmap; import android.graphics.Bitmap_Delegate; +import android.graphics.NinePatch_Delegate; +import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; import android.util.TypedValue; import java.io.File; @@ -121,15 +124,38 @@ public final class ResourceHelper { if (lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) { File file = new File(stringValue); if (file.isFile()) { - NinePatch ninePatch = Bridge.getCached9Patch(stringValue, + // see if we still have both the chunk and the bitmap in the caches + NinePatchChunk chunk = Bridge.getCached9Patch(stringValue, + isFramework ? null : context.getProjectKey()); + Bitmap bitmap = Bridge.getCachedBitmap(stringValue, isFramework ? null : context.getProjectKey()); - if (ninePatch == null) { + // if either chunk or bitmap is null, then we reload the 9-patch file. + if (chunk == null || bitmap == null) { try { - ninePatch = NinePatch.load(file.toURL(), false /* convert */); + NinePatch ninePatch = NinePatch.load(file.toURL(), false /* convert */); + if (ninePatch != null) { + if (chunk == null) { + chunk = ninePatch.getChunk(); - Bridge.setCached9Patch(stringValue, ninePatch, - isFramework ? null : context.getProjectKey()); + Bridge.setCached9Patch(stringValue, chunk, + isFramework ? null : context.getProjectKey()); + } + + if (bitmap == null) { + Density density = Density.MEDIUM; + if (value instanceof IDensityBasedResourceValue) { + density = ((IDensityBasedResourceValue)value).getDensity(); + } + + bitmap = Bitmap_Delegate.createBitmap(ninePatch.getImage(), + false /*isMutable*/, + density); + + Bridge.setCachedBitmap(stringValue, bitmap, + isFramework ? null : context.getProjectKey()); + } + } } catch (MalformedURLException e) { // URL is wrong, we'll return null below } catch (IOException e) { @@ -137,8 +163,13 @@ public final class ResourceHelper { } } - if (ninePatch != null) { - return new NinePatchDrawable(ninePatch); + if (chunk != null && bitmap != null) { + int[] padding = chunk.getPadding(); + Rect paddingRect = new Rect(padding[0], padding[1], padding[2], padding[3]); + + return new NinePatchDrawable(context.getResources(), bitmap, + NinePatch_Delegate.serialize(chunk), + paddingRect, null); } } @@ -174,27 +205,15 @@ public final class ResourceHelper { isFramework ? null : context.getProjectKey()); if (bitmap == null) { - // always create the cache copy in the original density. - bitmap = Bitmap_Delegate.createBitmap(bmpFile, Density.MEDIUM); - Bridge.setCachedBitmap(stringValue, bitmap, - isFramework ? null : context.getProjectKey()); - } - - try { + Density density = Density.MEDIUM; if (value instanceof IDensityBasedResourceValue) { - Density density = ((IDensityBasedResourceValue)value).getDensity(); - if (density != Density.MEDIUM) { - // create a copy of the bitmap - bitmap = Bitmap.createBitmap(bitmap); - - // apply the density - bitmap.setDensity(density.getValue()); - } + density = ((IDensityBasedResourceValue)value).getDensity(); } - } catch (NoClassDefFoundError error) { - // look like we're running in an older version of ADT that doesn't include - // the new layoutlib_api. Let's just ignore this, the drawing will just be - // wrong. + + bitmap = Bitmap_Delegate.createBitmap(bmpFile, false /*isMutable*/, + density); + Bridge.setCachedBitmap(stringValue, bitmap, + isFramework ? null : context.getProjectKey()); } return new BitmapDrawable(context.getResources(), bitmap); diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java index 23351ab..a3219e7 100644 --- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java +++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java @@ -48,5 +48,4 @@ public class NinePatchTest extends TestCase { assertEquals(36, mPatch.getWidth()); assertEquals(25, mPatch.getHeight()); } - } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index b9c7113..bb2e6b3 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -109,6 +109,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.DashPathEffect", "android.graphics.LinearGradient", "android.graphics.Matrix", + "android.graphics.NinePatch", "android.graphics.Paint", "android.graphics.PathEffect", "android.graphics.PorterDuffXfermode", |