Implement the layoutlib Bitmap through a native delegate.

This does not implement all the native methods of the
android.graphics.Bitmap class, only what's needed to draw an
ImageView object. The rest will be implemented after Canvas and
Paint have been moved to the native delegate.

Change-Id: Ia0c3b2cafa03871c298deaef5817a25ac1c35521
diff --git a/bridge/src/android/graphics/Bitmap.java b/bridge/src/android/graphics/Bitmap.java
deleted file mode 100644
index 35f022e..0000000
--- a/bridge/src/android/graphics/Bitmap.java
+++ /dev/null
@@ -1,278 +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 android.graphics;
-
-
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.imageio.ImageIO;
-
-public final class Bitmap extends _Original_Bitmap {
-
-    private BufferedImage mImage;
-
-    public Bitmap(File input) throws IOException {
-        super(1, true, null, -1);
-
-        mImage = ImageIO.read(input);
-    }
-
-    public Bitmap(InputStream is) throws IOException {
-        super(1, true, null, -1);
-
-        mImage = ImageIO.read(is);
-    }
-
-    Bitmap(BufferedImage image) {
-        super(1, true, null, -1);
-        mImage = image;
-    }
-
-    public BufferedImage getImage() {
-        return mImage;
-    }
-
-    // ----- overriden methods
-
-    public enum Config {
-        // these native values must match up with the enum in SkBitmap.h
-        ALPHA_8     (2),
-        RGB_565     (4),
-        ARGB_4444   (5),
-        ARGB_8888   (6);
-
-        Config(int ni) {
-            this.nativeInt = ni;
-        }
-        final int nativeInt;
-
-        /* package */ static Config nativeToConfig(int ni) {
-            return sConfigs[ni];
-        }
-
-        private static Config sConfigs[] = {
-            null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
-        };
-    }
-
-    @Override
-    public int getWidth() {
-        return mImage.getWidth();
-    }
-
-    @Override
-    public int getHeight() {
-        return mImage.getHeight();
-    }
-
-    /**
-     * Returns an immutable bitmap from the source bitmap. The new bitmap may
-     * be the same object as source, or a copy may have been made.
-     */
-    public static Bitmap createBitmap(Bitmap src) {
-        return createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), null, false);
-    }
-
-    /**
-     * Returns an immutable bitmap from the specified subset of the source
-     * bitmap. The new bitmap may be the same object as source, or a copy may
-     * have been made.
-     *
-     * @param source   The bitmap we are subsetting
-     * @param x        The x coordinate of the first pixel in source
-     * @param y        The y coordinate of the first pixel in source
-     * @param width    The number of pixels in each row
-     * @param height   The number of rows
-     */
-    public static Bitmap createBitmap(Bitmap source, int x, int y,
-                                      int width, int height) {
-        return new Bitmap(source.mImage.getSubimage(x, y, width, height));
-    }
-
-    /**
-     * Returns an immutable bitmap from subset of the source bitmap,
-     * transformed by the optional matrix.
-     *
-     * @param source   The bitmap we are subsetting
-     * @param x        The x coordinate of the first pixel in source
-     * @param y        The y coordinate of the first pixel in source
-     * @param width    The number of pixels in each row
-     * @param height   The number of rows
-     * @param m        Option matrix to be applied to the pixels
-     * @param filter   true if the source should be filtered.
-     *                   Only applies if the matrix contains more than just
-     *                   translation.
-     * @return A bitmap that represents the specified subset of source
-     * @throws IllegalArgumentException if the x, y, width, height values are
-     *         outside of the dimensions of the source bitmap.
-     */
-    public static Bitmap createBitmap(Bitmap source, int x, int y, int width,
-                                      int height, Matrix m, boolean filter) {
-        checkXYSign(x, y);
-        checkWidthHeight(width, height);
-        if (x + width > source.getWidth()) {
-            throw new IllegalArgumentException(
-                    "x + width must be <= bitmap.width()");
-        }
-        if (y + height > source.getHeight()) {
-            throw new IllegalArgumentException(
-                    "y + height must be <= bitmap.height()");
-        }
-
-        // check if we can just return our argument unchanged
-        if (!source.isMutable() && x == 0 && y == 0
-                && width == source.getWidth() && height == source.getHeight()
-                && (m == null || m.isIdentity())) {
-            return source;
-        }
-
-        if (m == null || m.isIdentity()) {
-            return new Bitmap(source.mImage.getSubimage(x, y, width, height));
-        }
-
-        int neww = width;
-        int newh = height;
-        Paint paint;
-
-        Rect srcR = new Rect(x, y, x + width, y + height);
-        RectF dstR = new RectF(0, 0, width, height);
-
-        /*  the dst should have alpha if the src does, or if our matrix
-            doesn't preserve rectness
-        */
-        boolean hasAlpha = source.hasAlpha() || !m.rectStaysRect();
-        RectF deviceR = new RectF();
-        m.mapRect(deviceR, dstR);
-        neww = Math.round(deviceR.width());
-        newh = Math.round(deviceR.height());
-
-        Canvas canvas = new Canvas(neww, newh);
-
-        canvas.translate(-deviceR.left, -deviceR.top);
-        canvas.concat(m);
-        paint = new Paint();
-        paint.setFilterBitmap(filter);
-        if (!m.rectStaysRect()) {
-            paint.setAntiAlias(true);
-        }
-
-        canvas.drawBitmap(source, srcR, dstR, paint);
-
-        return new Bitmap(canvas.getImage());
-    }
-
-    /**
-     * Returns a mutable bitmap with the specified width and height.
-     *
-     * @param width    The width of the bitmap
-     * @param height   The height of the bitmap
-     * @param config   The bitmap config to create.
-     * @throws IllegalArgumentException if the width or height are <= 0
-     */
-    public static Bitmap createBitmap(int width, int height, Config config) {
-        return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
-    }
-
-    /**
-     * Returns a immutable bitmap with the specified width and height, with each
-     * pixel value set to the corresponding value in the colors array.
-     *
-     * @param colors   Array of {@link Color} used to initialize the pixels.
-     * @param offset   Number of values to skip before the first color in the
-     *                 array of colors.
-     * @param stride   Number of colors in the array between rows (must be >=
-     *                 width or <= -width).
-     * @param width    The width of the bitmap
-     * @param height   The height of the bitmap
-     * @param config   The bitmap config to create. If the config does not
-     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
-     *                 bytes in the colors[] will be ignored (assumed to be FF)
-     * @throws IllegalArgumentException if the width or height are <= 0, or if
-     *         the color array's length is less than the number of pixels.
-     */
-    public static Bitmap createBitmap(int colors[], int offset, int stride,
-                                      int width, int height, Config config) {
-        checkWidthHeight(width, height);
-        if (Math.abs(stride) < width) {
-            throw new IllegalArgumentException("abs(stride) must be >= width");
-        }
-        int lastScanline = offset + (height - 1) * stride;
-        int length = colors.length;
-        if (offset < 0 || (offset + width > length)
-            || lastScanline < 0
-            || (lastScanline + width > length)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
-        // TODO: create an immutable bitmap...
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Returns a immutable bitmap with the specified width and height, with each
-     * pixel value set to the corresponding value in the colors array.
-     *
-     * @param colors   Array of {@link Color} used to initialize the pixels.
-     *                 This array must be at least as large as width * height.
-     * @param width    The width of the bitmap
-     * @param height   The height of the bitmap
-     * @param config   The bitmap config to create. If the config does not
-     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
-     *                 bytes in the colors[] will be ignored (assumed to be FF)
-     * @throws IllegalArgumentException if the width or height are <= 0, or if
-     *         the color array's length is less than the number of pixels.
-     */
-    public static Bitmap createBitmap(int colors[], int width, int height,
-                                      Config config) {
-        return createBitmap(colors, 0, width, width, height, config);
-    }
-
-    public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
-            int dstHeight, boolean filter) {
-        Matrix m;
-        synchronized (Bitmap.class) {
-            // small pool of just 1 matrix
-            m = sScaleMatrix;
-            sScaleMatrix = null;
-        }
-
-        if (m == null) {
-            m = new Matrix();
-        }
-
-        final int width = src.getWidth();
-        final int height = src.getHeight();
-        final float sx = dstWidth  / (float)width;
-        final float sy = dstHeight / (float)height;
-        m.setScale(sx, sy);
-        Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
-
-        synchronized (Bitmap.class) {
-            // do we need to check for null? why not just assign everytime?
-            if (sScaleMatrix == null) {
-                sScaleMatrix = m;
-            }
-        }
-
-        return b;
-    }
-
-
-}
diff --git a/bridge/src/android/graphics/BitmapFactory.java b/bridge/src/android/graphics/BitmapFactory.java
index e978fe8..6fd59c4 100644
--- a/bridge/src/android/graphics/BitmapFactory.java
+++ b/bridge/src/android/graphics/BitmapFactory.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.util.DisplayMetrics;
@@ -454,7 +456,7 @@
             // into is.read(...) This number is not related to the value passed
             // to mark(...) above.
             try {
-                bm = new Bitmap(is);
+                bm = Bitmap_Delegate.createBitmap(is, Density.MEDIUM);
             } catch (IOException e) {
                 return null;
             }
diff --git a/bridge/src/android/graphics/Bitmap_Delegate.java b/bridge/src/android/graphics/Bitmap_Delegate.java
new file mode 100644
index 0000000..24fba72
--- /dev/null
+++ b/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -0,0 +1,327 @@
+/*
+ * 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.api.IDensityBasedResourceValue.Density;
+import com.android.layoutlib.bridge.DelegateManager;
+
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.Buffer;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Bitmap
+ *
+ * Through the layoutlib_create tool, the original native methods of Bitmap have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Bitmap class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Bitmap_Delegate {
+
+    // ---- delegate manager ----
+    private static final DelegateManager<Bitmap_Delegate> sManager =
+            new DelegateManager<Bitmap_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+    private BufferedImage mImage;
+    private boolean mHasAlpha = true;
+
+    // ---- Public Helper methods ----
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given file content.
+     */
+    public static Bitmap createBitmap(File input, 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());
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given stream content.
+     */
+    public static Bitmap createBitmap(InputStream input, 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());
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
+     */
+    public static Bitmap createBitmap(BufferedImage image, Density density) throws IOException {
+        // create a delegate with the given image.
+        Bitmap_Delegate delegate = new Bitmap_Delegate(image);
+
+        return createBitmap(delegate, density.getValue());
+    }
+
+    /**
+     * 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) {
+            assert false;
+            return null;
+        }
+
+        return delegate.mImage;
+    }
+
+    public static int getBufferedImageType(int nativeBitmapConfig) {
+        switch (Config.sConfigs[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;
+        }
+
+        return BufferedImage.TYPE_INT_ARGB;
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
+            int height, int nativeConfig, boolean mutable) {
+        int imageType = getBufferedImageType(nativeConfig);
+
+        // create the image
+        BufferedImage image = new BufferedImage(width, height, imageType);
+
+        // fill it
+        //image.setRGB(x, y, rgb)
+
+        // create a delegate with the content of the stream.
+        Bitmap_Delegate delegate = new Bitmap_Delegate(image);
+
+        return createBitmap(delegate, Bitmap.getDefaultDensity());
+    }
+
+    /*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static void nativeDestructor(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static void nativeRecycle(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality,
+            OutputStream stream, byte[] tempStorage) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static void nativeErase(int nativeBitmap, int color) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        BufferedImage image = delegate.mImage;
+
+        Graphics2D g = image.createGraphics();
+        try {
+            if (delegate.mHasAlpha == false) {
+                color |= color & 0xFF000000;
+            }
+            g.setColor(new java.awt.Color(color));
+
+            g.fillRect(0, 0, image.getWidth(), image.getHeight());
+        } finally {
+            g.dispose();
+        }
+    }
+
+    /*package*/ static int nativeWidth(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getWidth();
+    }
+
+    /*package*/ static int nativeHeight(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getHeight();
+    }
+
+    /*package*/ static int nativeRowBytes(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getWidth();
+    }
+
+    /*package*/ static int nativeConfig(int nativeBitmap) {
+        return Config.ARGB_8888.nativeInt;
+    }
+
+    /*package*/ static boolean nativeHasAlpha(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return true;
+        }
+
+        return delegate.mHasAlpha;
+    }
+
+    /*package*/ static int nativeGetPixel(int nativeBitmap, int x, int y) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getRGB(x, y);
+    }
+
+    /*package*/ static void nativeGetPixels(int nativeBitmap, int[] pixels, int offset,
+            int stride, int x, int y, int width, int height) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeGetPixels");
+    }
+
+
+    /*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSetPixel");
+    }
+
+    /*package*/ static void nativeSetPixels(int nativeBitmap, int[] colors, int offset,
+            int stride, int x, int y, int width, int height) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSetPixels");
+    }
+
+    /*package*/ static void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCopyPixelsToBuffer");
+    }
+
+    /*package*/ static void nativeCopyPixelsFromBuffer(int nb, Buffer src) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCopyPixelsFromBuffer");
+    }
+
+    /*package*/ static int nativeGenerationId(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeGenerationId");
+    }
+
+    /*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCreateFromParcel");
+    }
+
+    /*package*/ static boolean nativeWriteToParcel(int nativeBitmap, boolean isMutable,
+            int density, Parcel p) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeWriteToParcel");
+    }
+
+    /*package*/ static Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint,
+            int[] offsetXY) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeExtractAlpha");
+    }
+
+
+    /*package*/ static void nativePrepareToDraw(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativePrepareToDraw");
+    }
+
+    /*package*/ static void nativeSetHasAlpha(int nativeBitmap, boolean hasAlpha) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mHasAlpha = hasAlpha;
+    }
+
+    /*package*/ static boolean nativeSameAs(int nb0, int nb1) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSameAs");
+    }
+
+    // ---- Private delegate/helper methods ----
+
+    private Bitmap_Delegate(BufferedImage image) {
+        mImage = image;
+    }
+
+    private static Bitmap createBitmap(Bitmap_Delegate delegate, 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);
+    }
+}
diff --git a/bridge/src/android/graphics/Canvas.java b/bridge/src/android/graphics/Canvas.java
index 0dccc0d6..24da812 100644
--- a/bridge/src/android/graphics/Canvas.java
+++ b/bridge/src/android/graphics/Canvas.java
@@ -51,7 +51,7 @@
 
     public Canvas(Bitmap bitmap) {
         mLogger = null;
-        mBufferedImage = bitmap.getImage();
+        mBufferedImage = Bitmap_Delegate.getImage(bitmap);
         mGraphicsStack.push(mBufferedImage.createGraphics());
     }
 
@@ -227,7 +227,7 @@
      */
     @Override
     public void setBitmap(Bitmap bitmap) {
-        mBufferedImage = bitmap.getImage();
+        mBufferedImage = Bitmap_Delegate.getImage(bitmap);
         mGraphicsStack.push(mBufferedImage.createGraphics());
     }
 
@@ -557,7 +557,7 @@
 
     private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft,
             int dtop, int dright, int dbottom, Paint paint) {
-        BufferedImage image = bitmap.getImage();
+        BufferedImage image = Bitmap_Delegate.getImage(bitmap);
 
         Graphics2D g = getGraphics2d();
 
diff --git a/bridge/src/android/graphics/Matrix_Delegate.java b/bridge/src/android/graphics/Matrix_Delegate.java
index ed2eff2..cc4a80c 100644
--- a/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/bridge/src/android/graphics/Matrix_Delegate.java
@@ -76,7 +76,7 @@
 
     // ---- native methods ----
 
-    public static int native_create(int native_src_or_zero) {
+    /*package*/ static int native_create(int native_src_or_zero) {
         // create the delegate
         Matrix_Delegate newDelegate = new Matrix_Delegate();
 
@@ -94,7 +94,7 @@
         return sManager.addDelegate(newDelegate);
     }
 
-    public static boolean native_isIdentity(int native_object) {
+    /*package*/ static boolean native_isIdentity(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -112,7 +112,7 @@
         return true;
     }
 
-    public static boolean native_rectStaysRect(int native_object) {
+    /*package*/ static boolean native_rectStaysRect(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -122,7 +122,7 @@
         return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
     }
 
-    public static void native_reset(int native_object) {
+    /*package*/ static void native_reset(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -132,7 +132,7 @@
         reset(d.mValues);
     }
 
-    public static void native_set(int native_object, int other) {
+    /*package*/ static void native_set(int native_object, int other) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -148,7 +148,7 @@
         System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
     }
 
-    public static void native_setTranslate(int native_object, float dx, float dy) {
+    /*package*/ static void native_setTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -158,7 +158,7 @@
         setTranslate(d.mValues, dx, dy);
     }
 
-    public static void native_setScale(int native_object, float sx, float sy, float px, float py) {
+    /*package*/ static void native_setScale(int native_object, float sx, float sy, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -168,7 +168,7 @@
         d.mValues = getScale(sx, sy, px, py);
     }
 
-    public static void native_setScale(int native_object, float sx, float sy) {
+    /*package*/ static void native_setScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -186,7 +186,7 @@
         d.mValues[8] = 1;
     }
 
-    public static void native_setRotate(int native_object, float degrees, float px, float py) {
+    /*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -196,7 +196,7 @@
         d.mValues = getRotate(degrees, px, py);
     }
 
-    public static void native_setRotate(int native_object, float degrees) {
+    /*package*/ static void native_setRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -206,7 +206,7 @@
         setRotate(d.mValues, degrees);
     }
 
-    public static void native_setSinCos(int native_object, float sinValue, float cosValue,
+    /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -225,7 +225,7 @@
         d.postTransform(getTranslate(px, py));
     }
 
-    public static void native_setSinCos(int native_object, float sinValue, float cosValue) {
+    /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -235,7 +235,7 @@
         setRotate(d.mValues, sinValue, cosValue);
     }
 
-    public static void native_setSkew(int native_object, float kx, float ky, float px, float py) {
+    /*package*/ static void native_setSkew(int native_object, float kx, float ky, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -245,7 +245,7 @@
         d.mValues = getSkew(kx, ky, px, py);
     }
 
-    public static void native_setSkew(int native_object, float kx, float ky) {
+    /*package*/ static void native_setSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -263,7 +263,7 @@
         d.mValues[8] = 1;
     }
 
-    public static boolean native_setConcat(int native_object, int a, int b) {
+    /*package*/ static boolean native_setConcat(int native_object, int a, int b) {
         if (a == native_object) {
             return native_preConcat(native_object, b);
         } else if (b == native_object) {
@@ -293,7 +293,7 @@
         return true;
     }
 
-    public static boolean native_preTranslate(int native_object, float dx, float dy) {
+    /*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -304,7 +304,7 @@
         return true;
     }
 
-    public static boolean native_preScale(int native_object, float sx, float sy,
+    /*package*/ static boolean native_preScale(int native_object, float sx, float sy,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -316,7 +316,7 @@
         return true;
     }
 
-    public static boolean native_preScale(int native_object, float sx, float sy) {
+    /*package*/ static boolean native_preScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -327,7 +327,7 @@
         return true;
     }
 
-    public static boolean native_preRotate(int native_object, float degrees, float px, float py) {
+    /*package*/ static boolean native_preRotate(int native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -338,7 +338,7 @@
         return true;
     }
 
-    public static boolean native_preRotate(int native_object, float degrees) {
+    /*package*/ static boolean native_preRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -353,7 +353,7 @@
         return true;
     }
 
-    public static boolean native_preSkew(int native_object, float kx, float ky,
+    /*package*/ static boolean native_preSkew(int native_object, float kx, float ky,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -365,7 +365,7 @@
         return true;
     }
 
-    public static boolean native_preSkew(int native_object, float kx, float ky) {
+    /*package*/ static boolean native_preSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -376,7 +376,7 @@
         return true;
     }
 
-    public static boolean native_preConcat(int native_object, int other_matrix) {
+    /*package*/ static boolean native_preConcat(int native_object, int other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -393,7 +393,7 @@
         return true;
     }
 
-    public static boolean native_postTranslate(int native_object, float dx, float dy) {
+    /*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -404,7 +404,7 @@
         return true;
     }
 
-    public static boolean native_postScale(int native_object, float sx, float sy,
+    /*package*/ static boolean native_postScale(int native_object, float sx, float sy,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -416,7 +416,7 @@
         return true;
     }
 
-    public static boolean native_postScale(int native_object, float sx, float sy) {
+    /*package*/ static boolean native_postScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -427,7 +427,7 @@
         return true;
     }
 
-    public static boolean native_postRotate(int native_object, float degrees, float px, float py) {
+    /*package*/ static boolean native_postRotate(int native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -438,7 +438,7 @@
         return true;
     }
 
-    public static boolean native_postRotate(int native_object, float degrees) {
+    /*package*/ static boolean native_postRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -449,7 +449,7 @@
         return true;
     }
 
-    public static boolean native_postSkew(int native_object, float kx, float ky,
+    /*package*/ static boolean native_postSkew(int native_object, float kx, float ky,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -461,7 +461,7 @@
         return true;
     }
 
-    public static boolean native_postSkew(int native_object, float kx, float ky) {
+    /*package*/ static boolean native_postSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -472,7 +472,7 @@
         return true;
     }
 
-    public static boolean native_postConcat(int native_object, int other_matrix) {
+    /*package*/ static boolean native_postConcat(int native_object, int other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -489,7 +489,7 @@
         return true;
     }
 
-    public static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) {
+    /*package*/ static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -553,13 +553,13 @@
         return true;
     }
 
-    public static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
+    /*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
             float[] dst, int dstIndex, int pointCount) {
         // FIXME
-        throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED");
+        throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_setPolyToPoly");
     }
 
-    public static boolean native_invert(int native_object, int inverse) {
+    /*package*/ static boolean native_invert(int native_object, int inverse) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -589,7 +589,7 @@
         }
     }
 
-    public static void native_mapPoints(int native_object, float[] dst, int dstIndex,
+    /*package*/ static void native_mapPoints(int native_object, float[] dst, int dstIndex,
             float[] src, int srcIndex, int ptCount, boolean isPts) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -602,11 +602,11 @@
         } else {
             // src is vectors
             // FIXME
-            throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED");
+            throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapPoints");
         }
     }
 
-    public static boolean native_mapRect(int native_object, RectF dst, RectF src) {
+    /*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -635,12 +635,12 @@
         return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
     }
 
-    public static float native_mapRadius(int native_object, float radius) {
+    /*package*/ static float native_mapRadius(int native_object, float radius) {
         // FIXME
-        throw new UnsupportedOperationException();
+        throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapRadius");
     }
 
-    public static void native_getValues(int native_object, float[] values) {
+    /*package*/ static void native_getValues(int native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -650,7 +650,7 @@
         System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
     }
 
-    public static void native_setValues(int native_object, float[] values) {
+    /*package*/ static void native_setValues(int native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -660,7 +660,7 @@
         System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
     }
 
-    public static boolean native_equals(int native_a, int native_b) {
+    /*package*/ static boolean native_equals(int native_a, int native_b) {
         Matrix_Delegate a = sManager.getDelegate(native_a);
         if (a == null) {
             assert false;
@@ -682,7 +682,7 @@
         return true;
     }
 
-    public static void finalizer(int native_instance) {
+    /*package*/ static void finalizer(int native_instance) {
         sManager.removeDelegate(native_instance);
     }
 
diff --git a/bridge/src/android/graphics/Typeface_Delegate.java b/bridge/src/android/graphics/Typeface_Delegate.java
index 309d934..248bdab 100644
--- a/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/bridge/src/android/graphics/Typeface_Delegate.java
@@ -34,7 +34,7 @@
  *
  * This class behaves like the original native implementation, but in Java, keeping previously
  * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Matrix class.
+ * it and the original Typeface class.
  *
  * @see DelegateManager
  *
@@ -84,7 +84,7 @@
 
     // ---- native methods ----
 
-    public static synchronized int nativeCreate(String familyName, int style) {
+    /*package*/ static synchronized int nativeCreate(String familyName, int style) {
         if (familyName == null) {
             familyName = DEFAULT_FAMILY;
         }
@@ -102,7 +102,7 @@
         return sManager.addDelegate(newDelegate);
     }
 
-    public static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
+    /*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
         Typeface_Delegate delegate = sManager.getDelegate(native_instance);
         if (delegate == null) {
             assert false;
@@ -122,21 +122,21 @@
         return sManager.addDelegate(newDelegate);
     }
 
-    public static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
+    /*package*/ static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
         // FIXME
-        throw new UnsupportedOperationException();
+        throw new UnsupportedOperationException("Native delegate needed: Typeface_Delegate.nativeCreateFromAsset");
     }
 
-    public static synchronized int nativeCreateFromFile(String path) {
+    /*package*/ static synchronized int nativeCreateFromFile(String path) {
         // FIXME
-        throw new UnsupportedOperationException();
+        throw new UnsupportedOperationException("Native delegate needed: Typeface_Delegate.nativeCreateFromFile");
     }
 
-    public static void nativeUnref(int native_instance) {
+    /*package*/ static void nativeUnref(int native_instance) {
         sManager.removeDelegate(native_instance);
     }
 
-    public static int nativeGetStyle(int native_instance) {
+    /*package*/ static int nativeGetStyle(int native_instance) {
         Typeface_Delegate delegate = sManager.getDelegate(native_instance);
         if (delegate == null) {
             assert false;
@@ -146,7 +146,7 @@
         return delegate.mStyle;
     }
 
-    public static void setGammaForText(float blackGamma, float whiteGamma) {
+    /*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
         // This is for device testing only: pass
     }
 
diff --git a/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java b/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
index f624753..f13ecdc 100644
--- a/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
+++ b/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
@@ -17,8 +17,8 @@
 package com.android.layoutlib.bridge;
 
 import com.android.layoutlib.api.IDensityBasedResourceValue;
-import com.android.layoutlib.api.IResourceValue;
 import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+import com.android.layoutlib.api.IResourceValue;
 import com.android.ninepatch.NinePatch;
 
 import org.kxml2.io.KXmlParser;
@@ -26,6 +26,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -105,7 +106,8 @@
      * @param isFramework indicates whether the resource is a framework resources.
      * Framework resources are cached, and loaded only once.
      */
-    public static Drawable getDrawable(IResourceValue value, BridgeContext context, boolean isFramework) {
+    public static Drawable getDrawable(IResourceValue value, BridgeContext context,
+            boolean isFramework) {
         Drawable d = null;
 
         String stringValue = value.getValue();
@@ -168,14 +170,8 @@
                             isFramework ? null : context.getProjectKey());
 
                     if (bitmap == null) {
-                        bitmap = new Bitmap(bmpFile);
-                        try {
-                            bitmap.setDensity(Density.MEDIUM.getValue());
-                        } catch (NoClassDefFoundError error) {
-                            // look like we're running in an older version of ADT that doesn't
-                            // include the new layoutlib_api. Let's just ignore this, the drawing
-                            // will just be wrong.
-                        }
+                        // always create the cache copy in the original density.
+                        bitmap = Bitmap_Delegate.createBitmap(bmpFile, Density.MEDIUM);
                         Bridge.setCachedBitmap(stringValue, bitmap,
                                 isFramework ? null : context.getProjectKey());
                     }
diff --git a/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java b/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
index 6eed8ba..7c1eecd 100644
--- a/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
+++ b/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
@@ -87,7 +87,7 @@
 
             try {
                 // try to load the method with the given parameter types.
-                delegateClass.getMethod(originalMethod.getName(), parameters);
+                delegateClass.getDeclaredMethod(originalMethod.getName(), parameters);
             } catch (NoSuchMethodException e) {
                 // compute a full class name that's long but not too long.
                 StringBuilder sb = new StringBuilder(originalMethod.getName() + "(");
diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index f6d11fe..0ecb474 100644
--- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -103,6 +103,7 @@
      * The list of classes on which to delegate all native methods.
      */
     private final static String[] DELEGATE_CLASS_NATIVES = new String[] {
+        "android.graphics.Bitmap",
         "android.graphics.Matrix",
         "android.graphics.Typeface",
     };
@@ -123,7 +124,6 @@
      */
     private final static String[] RENAMED_CLASSES =
         new String[] {
-            "android.graphics.Bitmap",              "android.graphics._Original_Bitmap",
             "android.graphics.BitmapFactory",       "android.graphics._Original_BitmapFactory",
             "android.graphics.BitmapShader",        "android.graphics._Original_BitmapShader",
             "android.graphics.Canvas",              "android.graphics._Original_Canvas",