summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/java/android/graphics/AvoidXfermode.java57
-rwxr-xr-xgraphics/java/android/graphics/Bitmap.aidl19
-rw-r--r--graphics/java/android/graphics/Bitmap.java811
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java371
-rw-r--r--graphics/java/android/graphics/BitmapShader.java41
-rw-r--r--graphics/java/android/graphics/BlurMaskFilter.java45
-rw-r--r--graphics/java/android/graphics/Camera.java54
-rw-r--r--graphics/java/android/graphics/Canvas.java1468
-rw-r--r--graphics/java/android/graphics/Color.java217
-rw-r--r--graphics/java/android/graphics/ColorFilter.java34
-rw-r--r--graphics/java/android/graphics/ColorMatrix.java233
-rw-r--r--graphics/java/android/graphics/ColorMatrixColorFilter.java46
-rw-r--r--graphics/java/android/graphics/ComposePathEffect.java32
-rw-r--r--graphics/java/android/graphics/ComposeShader.java51
-rw-r--r--graphics/java/android/graphics/CornerPathEffect.java33
-rw-r--r--graphics/java/android/graphics/DashPathEffect.java43
-rw-r--r--graphics/java/android/graphics/DiscretePathEffect.java31
-rw-r--r--graphics/java/android/graphics/DrawFilter.java36
-rw-r--r--graphics/java/android/graphics/EmbossMaskFilter.java38
-rw-r--r--graphics/java/android/graphics/Interpolator.java163
-rw-r--r--graphics/java/android/graphics/LayerRasterizer.java40
-rw-r--r--graphics/java/android/graphics/LightingColorFilter.java36
-rw-r--r--graphics/java/android/graphics/LinearGradient.java63
-rw-r--r--graphics/java/android/graphics/MaskFilter.java32
-rw-r--r--graphics/java/android/graphics/Matrix.java639
-rw-r--r--graphics/java/android/graphics/Movie.java74
-rw-r--r--graphics/java/android/graphics/NinePatch.java125
-rw-r--r--graphics/java/android/graphics/Paint.java1314
-rw-r--r--graphics/java/android/graphics/PaintFlagsDrawFilter.java37
-rw-r--r--graphics/java/android/graphics/Path.java599
-rw-r--r--graphics/java/android/graphics/PathDashPathEffect.java51
-rw-r--r--graphics/java/android/graphics/PathEffect.java32
-rw-r--r--graphics/java/android/graphics/PathMeasure.java152
-rw-r--r--graphics/java/android/graphics/Picture.java176
-rw-r--r--graphics/java/android/graphics/PixelFormat.java86
-rw-r--r--graphics/java/android/graphics/PixelXorXfermode.java32
-rw-r--r--graphics/java/android/graphics/Point.java85
-rw-r--r--graphics/java/android/graphics/PointF.java88
-rw-r--r--graphics/java/android/graphics/PorterDuff.java63
-rw-r--r--graphics/java/android/graphics/PorterDuffColorFilter.java34
-rw-r--r--graphics/java/android/graphics/PorterDuffXfermode.java30
-rw-r--r--graphics/java/android/graphics/RadialGradient.java66
-rw-r--r--graphics/java/android/graphics/Rasterizer.java33
-rw-r--r--graphics/java/android/graphics/Rect.aidl20
-rw-r--r--graphics/java/android/graphics/Rect.java513
-rw-r--r--graphics/java/android/graphics/RectF.java478
-rw-r--r--graphics/java/android/graphics/Region.aidl20
-rw-r--r--graphics/java/android/graphics/Region.java344
-rw-r--r--graphics/java/android/graphics/RegionIterator.java54
-rw-r--r--graphics/java/android/graphics/Shader.java80
-rw-r--r--graphics/java/android/graphics/SumPathEffect.java32
-rw-r--r--graphics/java/android/graphics/SweepGradient.java64
-rw-r--r--graphics/java/android/graphics/TemporaryBuffer.java47
-rw-r--r--graphics/java/android/graphics/Typeface.java153
-rw-r--r--graphics/java/android/graphics/Xfermode.java40
-rw-r--r--graphics/java/android/graphics/drawable/AnimationDrawable.java334
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java295
-rw-r--r--graphics/java/android/graphics/drawable/ClipDrawable.java273
-rw-r--r--graphics/java/android/graphics/drawable/ColorDrawable.java150
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java768
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java497
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java891
-rw-r--r--graphics/java/android/graphics/drawable/InsetDrawable.java285
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java607
-rw-r--r--graphics/java/android/graphics/drawable/LevelListDrawable.java191
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java160
-rw-r--r--graphics/java/android/graphics/drawable/PaintDrawable.java107
-rw-r--r--graphics/java/android/graphics/drawable/PictureDrawable.java106
-rw-r--r--graphics/java/android/graphics/drawable/RotateDrawable.java302
-rw-r--r--graphics/java/android/graphics/drawable/ScaleDrawable.java275
-rw-r--r--graphics/java/android/graphics/drawable/ShapeDrawable.java402
-rw-r--r--graphics/java/android/graphics/drawable/StateListDrawable.java207
-rw-r--r--graphics/java/android/graphics/drawable/TransitionDrawable.java222
-rw-r--r--graphics/java/android/graphics/drawable/package.html9
-rw-r--r--graphics/java/android/graphics/drawable/shapes/ArcShape.java51
-rw-r--r--graphics/java/android/graphics/drawable/shapes/OvalShape.java40
-rw-r--r--graphics/java/android/graphics/drawable/shapes/PathShape.java68
-rw-r--r--graphics/java/android/graphics/drawable/shapes/RectShape.java53
-rw-r--r--graphics/java/android/graphics/drawable/shapes/RoundRectShape.java108
-rw-r--r--graphics/java/android/graphics/drawable/shapes/Shape.java95
-rw-r--r--graphics/java/android/graphics/drawable/shapes/package.html5
-rw-r--r--graphics/java/android/graphics/package.html6
-rw-r--r--graphics/java/com/android/internal/graphics/NativeUtils.java40
83 files changed, 16102 insertions, 0 deletions
diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java
new file mode 100644
index 0000000..d7b0225
--- /dev/null
+++ b/graphics/java/android/graphics/AvoidXfermode.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+/**
+ * AvoidXfermode xfermode will draw the src everywhere except on top of the
+ * opColor or, depending on the Mode, draw only on top of the opColor.
+ */
+public class AvoidXfermode extends Xfermode {
+
+ // these need to match the enum in SkAvoidXfermode.h on the native side
+ public enum Mode {
+ AVOID (0), //!< draw everywhere except on the opColor
+ TARGET (1); //!< draw only on top of the opColor
+
+ Mode(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * This xfermode will draw the src everywhere except on top of the opColor
+ * or, depending on the Mode, draw only on top of the opColor.
+ *
+ * @param opColor The color to avoid (or to target depending on Mode). Note
+ * that the alpha in opColor is ignored.
+ * @param tolerance How closely we compare a pixel to the opColor.
+ * 0 - only operate if exact match
+ * 255 - maximum gradation (blending) based on how
+ * similar the pixel is to our opColor (max tolerance)
+ * @param mode If we should avoid or target the opColor
+ */
+ public AvoidXfermode(int opColor, int tolerance, Mode mode) {
+ if (tolerance < 0 || tolerance > 255) {
+ throw new IllegalArgumentException("tolerance must be 0..255");
+ }
+ native_instance = nativeCreate(opColor, tolerance, mode.nativeInt);
+ }
+
+ private static native int nativeCreate(int opColor, int tolerance,
+ int nativeMode);
+}
diff --git a/graphics/java/android/graphics/Bitmap.aidl b/graphics/java/android/graphics/Bitmap.aidl
new file mode 100755
index 0000000..ce97b95
--- /dev/null
+++ b/graphics/java/android/graphics/Bitmap.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2007, 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;
+
+parcelable Bitmap;
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
new file mode 100644
index 0000000..501c99f
--- /dev/null
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2006 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.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.io.OutputStream;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ShortBuffer;
+import java.nio.IntBuffer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public final class Bitmap implements Parcelable {
+
+ // Note: mNativeBitmap is used by FaceDetector_jni.cpp
+ // Don't change/rename without updating FaceDetector_jni.cpp
+ private final int mNativeBitmap;
+
+ private final boolean mIsMutable;
+ private byte[] mNinePatchChunk; // may be null
+ private int mWidth = -1;
+ private int mHeight = -1;
+ private boolean mRecycled;
+
+ private static volatile Matrix sScaleMatrix;
+
+ /**
+ * @noinspection UnusedDeclaration
+ */
+ /* Private constructor that must received an already allocated native
+ bitmap int (pointer).
+
+ This can be called from JNI code.
+ */
+ private Bitmap(int nativeBitmap, boolean isMutable, byte[] ninePatchChunk) {
+ if (nativeBitmap == 0) {
+ throw new RuntimeException("internal error: native bitmap is 0");
+ }
+
+ // we delete this in our finalizer
+ mNativeBitmap = nativeBitmap;
+ mIsMutable = isMutable;
+ mNinePatchChunk = ninePatchChunk;
+ }
+
+ /**
+ * Free up the memory associated with this bitmap's pixels, and mark the
+ * bitmap as "dead", meaning it will throw an exception if getPixels() or
+ * setPixels() is called, and will draw nothing. This operation cannot be
+ * reversed, so it should only be called if you are sure there are no
+ * further uses for the bitmap. This is an advanced call, and normally need
+ * not be called, since the normal GC process will free up this memory when
+ * there are no more references to this bitmap.
+ */
+ public void recycle() {
+ if (!mRecycled) {
+ nativeRecycle(mNativeBitmap);
+ mNinePatchChunk = null;
+ mRecycled = true;
+ }
+ }
+
+ /**
+ * Returns true if this bitmap has been recycled. If so, then it is an error
+ * to try to access its pixels, and the bitmap will not draw.
+ *
+ * @return true if the bitmap has been recycled
+ */
+ public final boolean isRecycled() {
+ return mRecycled;
+ }
+
+ /**
+ * This is called by methods that want to throw an exception if the bitmap
+ * has already been recycled.
+ */
+ private void checkRecycled(String errorMessage) {
+ if (mRecycled) {
+ throw new IllegalStateException(errorMessage);
+ }
+ }
+
+ /**
+ * Common code for checking that x and y are >= 0
+ *
+ * @param x x coordinate to ensure is >= 0
+ * @param y y coordinate to ensure is >= 0
+ */
+ private static void checkXYSign(int x, int y) {
+ if (x < 0) {
+ throw new IllegalArgumentException("x must be >= 0");
+ }
+ if (y < 0) {
+ throw new IllegalArgumentException("y must be >= 0");
+ }
+ }
+
+ /**
+ * Common code for checking that width and height are > 0
+ *
+ * @param width width to ensure is > 0
+ * @param height height to ensure is > 0
+ */
+ private static void checkWidthHeight(int width, int height) {
+ if (width <= 0) {
+ throw new IllegalArgumentException("width must be > 0");
+ }
+ if (height <= 0) {
+ throw new IllegalArgumentException("height must be > 0");
+ }
+ }
+
+ 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
+ };
+ }
+
+ /**
+ * Copy the bitmap's pixels into the specified buffer (allocated by the
+ * caller). An exception is thrown if the buffer is not large enough to
+ * hold all of the pixels (taking into account the number of bytes per
+ * pixel) or if the Buffer subclass is not one of the support types
+ * (ByteBuffer, ShortBuffer, IntBuffer).
+ */
+ public void copyPixelsToBuffer(Buffer dst) {
+ int elements = dst.remaining();
+ int shift;
+ if (dst instanceof ByteBuffer) {
+ shift = 0;
+ } else if (dst instanceof ShortBuffer) {
+ shift = 1;
+ } else if (dst instanceof IntBuffer) {
+ shift = 2;
+ } else {
+ throw new RuntimeException("unsupported Buffer subclass");
+ }
+
+ long bufferSize = (long)elements << shift;
+ long pixelSize = (long)getRowBytes() * getHeight();
+
+ if (bufferSize < pixelSize) {
+ throw new RuntimeException("Buffer not large enough for pixels");
+ }
+
+ nativeCopyPixelsToBuffer(mNativeBitmap, dst);
+
+ // now update the buffer's position
+ int position = dst.position();
+ position += pixelSize >> shift;
+ dst.position(position);
+ }
+
+ /**
+ * Tries to make a new bitmap based on the dimensions of this bitmap,
+ * setting the new bitmap's config to the one specified, and then copying
+ * this bitmap's pixels into the new bitmap. If the conversion is not
+ * supported, or the allocator fails, then this returns NULL.
+ *
+ * @param config The desired config for the resulting bitmap
+ * @param isMutable True if the resulting bitmap should be mutable (i.e.
+ * its pixels can be modified)
+ * @return the new bitmap, or null if the copy could not be made.
+ */
+ public Bitmap copy(Config config, boolean isMutable) {
+ checkRecycled("Can't copy a recycled bitmap");
+ return nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
+ }
+
+ public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
+ int dstHeight, boolean filter) {
+ Matrix m = null;
+ 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;
+ }
+
+ /**
+ * 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());
+ }
+
+ /**
+ * 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 createBitmap(source, x, y, width, height, null, false);
+ }
+
+ /**
+ * 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;
+ }
+
+ int neww = width;
+ int newh = height;
+ Canvas canvas = new Canvas();
+ Bitmap bitmap;
+ Paint paint;
+
+ Rect srcR = new Rect(x, y, x + width, y + height);
+ RectF dstR = new RectF(0, 0, width, height);
+
+ if (m == null || m.isIdentity()) {
+ bitmap = createBitmap(neww, newh, source.hasAlpha() ?
+ Config.ARGB_8888 : Config.RGB_565);
+ paint = null; // not needed
+ } else {
+ /* 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());
+ bitmap = createBitmap(neww, newh, hasAlpha ?
+ Config.ARGB_8888 : Config.RGB_565);
+ if (hasAlpha) {
+ bitmap.eraseColor(0);
+ }
+ canvas.translate(-deviceR.left, -deviceR.top);
+ canvas.concat(m);
+ paint = new Paint();
+ paint.setFilterBitmap(filter);
+ if (!m.rectStaysRect()) {
+ paint.setAntiAlias(true);
+ }
+ }
+ canvas.setBitmap(bitmap);
+ canvas.drawBitmap(source, srcR, dstR, paint);
+
+ return bitmap;
+ }
+
+ /**
+ * 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) {
+ Bitmap bm = nativeCreate(null, 0, width, width, height,
+ config.nativeInt, true);
+ bm.eraseColor(0); // start with black/transparent pixels
+ return bm;
+ }
+
+ /**
+ * 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();
+ }
+ return nativeCreate(colors, offset, stride, width, height,
+ config.nativeInt, false);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Returns an optional array of private data, used by the UI system for
+ * some bitmaps. Not intended to be called by applications.
+ */
+ public byte[] getNinePatchChunk() {
+ return mNinePatchChunk;
+ }
+
+ /**
+ * Specifies the known formats a bitmap can be compressed into
+ */
+ public enum CompressFormat {
+ JPEG (0),
+ PNG (1);
+
+ CompressFormat(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Number of bytes of temp storage we use for communicating between the
+ * native compressor and the java OutputStream.
+ */
+ private final static int WORKING_COMPRESS_STORAGE = 4096;
+
+ /**
+ * Write a compressed version of the bitmap to the specified outputstream.
+ * If this returns true, the bitmap can be reconstructed by passing a
+ * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
+ * all Formats support all bitmap configs directly, so it is possible that
+ * the returned bitmap from BitmapFactory could be in a different bitdepth,
+ * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
+ * pixels).
+ *
+ * @param format The format of the compressed image
+ * @param quality Hint to the compressor, 0-100. 0 meaning compress for
+ * small size, 100 meaning compress for max quality. Some
+ * formats, like PNG which is lossless, will ignore the
+ * quality setting
+ * @param stream The outputstream to write the compressed data.
+ * @return true if successfully compressed to the specified stream.
+ */
+ public boolean compress(CompressFormat format, int quality,
+ OutputStream stream) {
+ checkRecycled("Can't compress a recycled bitmap");
+ // do explicit check before calling the native method
+ if (stream == null) {
+ throw new NullPointerException();
+ }
+ if (quality < 0 || quality > 100) {
+ throw new IllegalArgumentException("quality must be 0..100");
+ }
+ return nativeCompress(mNativeBitmap, format.nativeInt, quality,
+ stream, new byte[WORKING_COMPRESS_STORAGE]);
+ }
+
+ /**
+ * Returns true if the bitmap is marked as mutable (i.e. can be drawn into)
+ */
+ public final boolean isMutable() {
+ return mIsMutable;
+ }
+
+ /** Returns the bitmap's width */
+ public final int getWidth() {
+ return mWidth == -1 ? mWidth = nativeWidth(mNativeBitmap) : mWidth;
+ }
+
+ /** Returns the bitmap's height */
+ public final int getHeight() {
+ return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight;
+ }
+
+ /**
+ * Return the number of bytes between rows in the bitmap's pixels. Note that
+ * this refers to the pixels as stored natively by the bitmap. If you call
+ * getPixels() or setPixels(), then the pixels are uniformly treated as
+ * 32bit values, packed according to the Color class.
+ *
+ * @return number of bytes between rows of the native bitmap pixels.
+ */
+ public final int getRowBytes() {
+ return nativeRowBytes(mNativeBitmap);
+ }
+
+ /**
+ * If the bitmap's internal config is in one of the public formats, return
+ * that config, otherwise return null.
+ */
+ public final Config getConfig() {
+ return Config.nativeToConfig(nativeConfig(mNativeBitmap));
+ }
+
+ /** Returns true if the bitmap's pixels support levels of alpha */
+ public final boolean hasAlpha() {
+ return nativeHasAlpha(mNativeBitmap);
+ }
+
+ /**
+ * Fills the bitmap's pixels with the specified {@link Color}.
+ *
+ * @throws IllegalStateException if the bitmap is not mutable.
+ */
+ public void eraseColor(int c) {
+ checkRecycled("Can't erase a recycled bitmap");
+ if (!isMutable()) {
+ throw new IllegalStateException("cannot erase immutable bitmaps");
+ }
+ nativeErase(mNativeBitmap, c);
+ }
+
+ /**
+ * Returns the {@link Color} at the specified location. Throws an exception
+ * if x or y are out of bounds (negative or >= to the width or height
+ * respectively).
+ *
+ * @param x The x coordinate (0...width-1) of the pixel to return
+ * @param y The y coordinate (0...height-1) of the pixel to return
+ * @return The argb {@link Color} at the specified coordinate
+ * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
+ */
+ public int getPixel(int x, int y) {
+ checkRecycled("Can't call getPixel() on a recycled bitmap");
+ checkPixelAccess(x, y);
+ return nativeGetPixel(mNativeBitmap, x, y);
+ }
+
+ /**
+ * Returns in pixels[] a copy of the data in the bitmap. Each value is
+ * a packed int representing a {@link Color}. The stride parameter allows
+ * the caller to allow for gaps in the returned pixels array between
+ * rows. For normal packed results, just pass width for the stride value.
+ *
+ * @param pixels The array to receive the bitmap's colors
+ * @param offset The first index to write into pixels[]
+ * @param stride The number of entries in pixels[] to skip between
+ * rows (must be >= bitmap's width). Can be negative.
+ * @param x The x coordinate of the first pixel to read from
+ * the bitmap
+ * @param y The y coordinate of the first pixel to read from
+ * the bitmap
+ * @param width The number of pixels to read from each row
+ * @param height The number of rows to read
+ * @throws IllegalArgumentException if x, y, width, height exceed the
+ * bounds of the bitmap, or if abs(stride) < width.
+ * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
+ * to receive the specified number of pixels.
+ */
+ public void getPixels(int[] pixels, int offset, int stride,
+ int x, int y, int width, int height) {
+ checkRecycled("Can't call getPixels() on a recycled bitmap");
+ if (width == 0 || height == 0) {
+ return; // nothing to do
+ }
+ checkPixelsAccess(x, y, width, height, offset, stride, pixels);
+ nativeGetPixels(mNativeBitmap, pixels, offset, stride,
+ x, y, width, height);
+ }
+
+ /**
+ * Shared code to check for illegal arguments passed to getPixel()
+ * or setPixel()
+ * @param x x coordinate of the pixel
+ * @param y y coordinate of the pixel
+ */
+ private void checkPixelAccess(int x, int y) {
+ checkXYSign(x, y);
+ if (x >= getWidth()) {
+ throw new IllegalArgumentException("x must be < bitmap.width()");
+ }
+ if (y >= getHeight()) {
+ throw new IllegalArgumentException("y must be < bitmap.height()");
+ }
+ }
+
+ /**
+ * Shared code to check for illegal arguments passed to getPixels()
+ * or setPixels()
+ *
+ * @param x left edge of the area of pixels to access
+ * @param y top edge of the area of pixels to access
+ * @param width width of the area of pixels to access
+ * @param height height of the area of pixels to access
+ * @param offset offset into pixels[] array
+ * @param stride number of elements in pixels[] between each logical row
+ * @param pixels array to hold the area of pixels being accessed
+ */
+ private void checkPixelsAccess(int x, int y, int width, int height,
+ int offset, int stride, int pixels[]) {
+ checkXYSign(x, y);
+ if (width < 0) {
+ throw new IllegalArgumentException("width must be >= 0");
+ }
+ if (height < 0) {
+ throw new IllegalArgumentException("height must be >= 0");
+ }
+ if (x + width > getWidth()) {
+ throw new IllegalArgumentException(
+ "x + width must be <= bitmap.width()");
+ }
+ if (y + height > getHeight()) {
+ throw new IllegalArgumentException(
+ "y + height must be <= bitmap.height()");
+ }
+ if (Math.abs(stride) < width) {
+ throw new IllegalArgumentException("abs(stride) must be >= width");
+ }
+ int lastScanline = offset + (height - 1) * stride;
+ int length = pixels.length;
+ if (offset < 0 || (offset + width > length)
+ || lastScanline < 0
+ || (lastScanline + width > length)) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Write the specified {@link Color} into the bitmap (assuming it is
+ * mutable) at the x,y coordinate.
+ *
+ * @param x The x coordinate of the pixel to replace (0...width-1)
+ * @param y The y coordinate of the pixel to replace (0...height-1)
+ * @param color The {@link Color} to write into the bitmap
+ * @throws IllegalStateException if the bitmap is not mutable
+ * @throws IllegalArgumentException if x, y are outside of the bitmap's
+ * bounds.
+ */
+ public void setPixel(int x, int y, int color) {
+ checkRecycled("Can't call setPixel() on a recycled bitmap");
+ if (!isMutable()) {
+ throw new IllegalStateException();
+ }
+ checkPixelAccess(x, y);
+ nativeSetPixel(mNativeBitmap, x, y, color);
+ }
+
+ /**
+ * Replace pixels in the bitmap with the colors in the array. Each element
+ * in the array is a packed int prepresenting a {@link Color}
+ *
+ * @param pixels The colors to write to the bitmap
+ * @param offset The index of the first color to read from pixels[]
+ * @param stride The number of colors in pixels[] to skip between rows.
+ * Normally this value will be the same as the width of
+ * the bitmap, but it can be larger (or negative).
+ * @param x The x coordinate of the first pixel to write to in
+ * the bitmap.
+ * @param y The y coordinate of the first pixel to write to in
+ * the bitmap.
+ * @param width The number of colors to copy from pixels[] per row
+ * @param height The number of rows to write to the bitmap
+ * @throws IllegalStateException if the bitmap is not mutable
+ * @throws IllegalArgumentException if x, y, width, height are outside of
+ * the bitmap's bounds.
+ * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
+ * to receive the specified number of pixels.
+ */
+ public void setPixels(int[] pixels, int offset, int stride,
+ int x, int y, int width, int height) {
+ checkRecycled("Can't call setPixels() on a recycled bitmap");
+ if (!isMutable()) {
+ throw new IllegalStateException();
+ }
+ if (width == 0 || height == 0) {
+ return; // nothing to do
+ }
+ checkPixelsAccess(x, y, width, height, offset, stride, pixels);
+ nativeSetPixels(mNativeBitmap, pixels, offset, stride,
+ x, y, width, height);
+ }
+
+ public static final Parcelable.Creator<Bitmap> CREATOR
+ = new Parcelable.Creator<Bitmap>() {
+ /**
+ * Rebuilds a bitmap previously stored with writeToParcel().
+ *
+ * @param p Parcel object to read the bitmap from
+ * @return a new bitmap created from the data in the parcel
+ */
+ public Bitmap createFromParcel(Parcel p) {
+ Bitmap bm = nativeCreateFromParcel(p);
+ if (bm == null) {
+ throw new RuntimeException("Failed to unparcel Bitmap");
+ }
+ return bm;
+ }
+ public Bitmap[] newArray(int size) {
+ return new Bitmap[size];
+ }
+ };
+
+ /**
+ * No special parcel contents.
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write the bitmap and its pixels to the parcel. The bitmap can be
+ * rebuilt from the parcel by calling CREATOR.createFromParcel().
+ * @param p Parcel object to write the bitmap data into
+ */
+ public void writeToParcel(Parcel p, int flags) {
+ checkRecycled("Can't parcel a recycled bitmap");
+ if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, p)) {
+ throw new RuntimeException("native writeToParcel failed");
+ }
+ }
+
+ /**
+ * Returns a new bitmap that captures the alpha values of the original.
+ * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
+ * taken from the paint that is passed to the draw call.
+ *
+ * @return new bitmap containing the alpha channel of the original bitmap.
+ */
+ public Bitmap extractAlpha() {
+ return extractAlpha(null, null);
+ }
+
+ /**
+ * Returns a new bitmap that captures the alpha values of the original.
+ * These values may be affected by the optional Paint parameter, which
+ * can contain its own alpha, and may also contain a MaskFilter which
+ * could change the actual dimensions of the resulting bitmap (e.g.
+ * a blur maskfilter might enlarge the resulting bitmap). If offsetXY
+ * is not null, it returns the amount to offset the returned bitmap so
+ * that it will logically align with the original. For example, if the
+ * paint contains a blur of radius 2, then offsetXY[] would contains
+ * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
+ * drawing the original would result in the blur visually aligning with
+ * the original.
+ * @param paint Optional paint used to modify the alpha values in the
+ * resulting bitmap. Pass null for default behavior.
+ * @param offsetXY Optional array that returns the X (index 0) and Y
+ * (index 1) offset needed to position the returned bitmap
+ * so that it visually lines up with the original.
+ * @return new bitmap containing the (optionally modified by paint) alpha
+ * channel of the original bitmap. This may be drawn with
+ * Canvas.drawBitmap(), where the color(s) will be taken from the
+ * paint that is passed to the draw call.
+ */
+ public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
+ checkRecycled("Can't extractAlpha on a recycled bitmap");
+ int nativePaint = paint != null ? paint.mNativePaint : 0;
+ Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY);
+ if (bm == null) {
+ throw new RuntimeException("Failed to extractAlpha on Bitmap");
+ }
+ return bm;
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ nativeDestructor(mNativeBitmap);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ //////////// native methods
+
+ private static native Bitmap nativeCreate(int[] colors, int offset,
+ int stride, int width, int height,
+ int nativeConfig, boolean mutable);
+ private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig,
+ boolean isMutable);
+ private static native void nativeDestructor(int nativeBitmap);
+ private static native void nativeRecycle(int nativeBitmap);
+
+ private static native boolean nativeCompress(int nativeBitmap, int format,
+ int quality, OutputStream stream,
+ byte[] tempStorage);
+ private static native void nativeErase(int nativeBitmap, int color);
+ private static native int nativeWidth(int nativeBitmap);
+ private static native int nativeHeight(int nativeBitmap);
+ private static native int nativeRowBytes(int nativeBitmap);
+ private static native int nativeConfig(int nativeBitmap);
+ private static native boolean nativeHasAlpha(int nativeBitmap);
+
+ private static native int nativeGetPixel(int nativeBitmap, int x, int y);
+ private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
+ int offset, int stride, int x,
+ int y, int width, int height);
+
+ private static native void nativeSetPixel(int nativeBitmap, int x, int y,
+ int color);
+ private static native void nativeSetPixels(int nativeBitmap, int[] colors,
+ int offset, int stride, int x,
+ int y, int width, int height);
+ private static native void nativeCopyPixelsToBuffer(int nativeBitmap,
+ Buffer dst);
+
+ private static native Bitmap nativeCreateFromParcel(Parcel p);
+ // returns true on success
+ private static native boolean nativeWriteToParcel(int nativeBitmap,
+ boolean isMutable,
+ Parcel p);
+ // returns a new bitmap built from the native bitmap's alpha, and the paint
+ private static native Bitmap nativeExtractAlpha(int nativeBitmap,
+ int nativePaint,
+ int[] offsetXY);
+
+ /* package */ final int ni() {
+ return mNativeBitmap;
+ }
+}
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
new file mode 100644
index 0000000..d1e6090
--- /dev/null
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2007 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 android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
+
+/**
+ * Creates Bitmap objects from various sources, including files, streams,
+ * and byte-arrays.
+ */
+public class BitmapFactory {
+ private static final String TAG = "BitmapFactory";
+ private static final boolean DEBUG_LOAD = false;
+
+ public static class Options {
+ /**
+ * Create a default Options object, which if left unchanged will give
+ * the same result from the decoder as if null were passed.
+ */
+ public Options() {
+ inDither = true;
+ }
+
+ /**
+ * If set to true, the decoder will return null (no bitmap), but
+ * the out... fields will still be set, allowing the caller to query
+ * the bitmap without having to allocate the memory for its pixels.
+ */
+ public boolean inJustDecodeBounds;
+ /**
+ * If set to a value > 1, requests the decoder to subsample the original
+ * image, returning a smaller image to save memory. The sample size is
+ * the number of pixels in either dimension that correspond to a single
+ * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
+ * an image that is 1/4 the width/height of the original, and 1/16 the
+ * number of pixels. Any value <= 1 is treated the same as 1. Note: the
+ * decoder will try to fulfill this request, but the resulting bitmap
+ * may have different dimensions that precisely what has been requested.
+ * Also, powers of 2 are often faster/easier for the decoder to honor.
+ */
+ public int inSampleSize;
+
+ /**
+ * If this is non-null, the decoder will try to decode into this
+ * internal configuration. If it is null, or the request cannot be met,
+ * the decoder will try to pick the best matching config based on the
+ * system's screen depth, and characteristics of the original image such
+ * as if it has per-pixel alpha (requiring a config that also does).
+ */
+ public Bitmap.Config inPreferredConfig;
+
+ /**
+ * If dither is true, the decoder will atttempt to dither the decoded
+ * image.
+ */
+ public boolean inDither;
+
+ /**
+ * The resulting width of the bitmap, set independent of the state of
+ * inJustDecodeBounds. However, if there is an error trying to decode,
+ * outWidth will be set to -1.
+ */
+ public int outWidth;
+ /**
+ * The resulting height of the bitmap, set independent of the state of
+ * inJustDecodeBounds. However, if there is an error trying to decode,
+ * outHeight will be set to -1.
+ */
+ public int outHeight;
+
+ /**
+ * If known, this string is set to the mimetype of the decoded image.
+ * If not know, or there is an error, it is set to null.
+ */
+ public String outMimeType;
+
+ /**
+ * Temp storage to use for decoding. Suggest 16K or so.
+ */
+ public byte [] inTempStorage;
+
+ private native void requestCancel();
+
+ /**
+ * Flag to indicate that cancel has been called on this object. This
+ * is useful if there's an intermediary that wants to first decode the
+ * bounds and then decode the image. In that case the intermediary
+ * can check, inbetween the bounds decode and the image decode, to see
+ * if the operation is canceled.
+ */
+ public boolean mCancel;
+
+ /**
+ * This can be called from another thread while this options object is
+ * inside a decode... call. Calling this will notify the decoder that
+ * it should cancel its operation. This is not guaranteed to cancel
+ * the decode, but if it does, the decoder... operation will return
+ * null, or if inJustDecodeBounds is true, will set outWidth/outHeight
+ * to -1
+ */
+ public void requestCancelDecode() {
+ mCancel = true;
+ requestCancel();
+ }
+ }
+
+ /**
+ * Decode a file path into a bitmap. If the specified file name is null,
+ * or cannot be decoded into a bitmap, the function returns null.
+ *
+ * @param pathName complete path name for the file to be decoded.
+ * @param opts null-ok; Options that control downsampling and whether the
+ * image should be completely decoded, or just is size returned.
+ * @return The decoded bitmap, or null if the image data could not be
+ * decoded, or, if opts is non-null, if opts requested only the
+ * size be returned (in opts.outWidth and opts.outHeight)
+ */
+ public static Bitmap decodeFile(String pathName, Options opts) {
+ Bitmap bm = null;
+ InputStream stream = null;
+ try {
+ stream = new FileInputStream(pathName);
+ bm = decodeStream(stream, null, opts);
+ } catch (Exception e) {
+ /* do nothing.
+ If the exception happened on open, bm will be null.
+ */
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // do nothing here
+ }
+ }
+ }
+ return bm;
+ }
+
+ /**
+ * Decode a file path into a bitmap. If the specified file name is null,
+ * or cannot be decoded into a bitmap, the function returns null.
+ *
+ * @param pathName complete path name for the file to be decoded.
+ * @return the resulting decoded bitmap, or null if it could not be decoded.
+ */
+ public static Bitmap decodeFile(String pathName) {
+ return decodeFile(pathName, null);
+ }
+
+ /**
+ * Decode an image referenced by a resource ID.
+ *
+ * @param res The resources object containing the image data
+ * @param id The resource id of the image data
+ * @param opts null-ok; Options that control downsampling and whether the
+ * image should be completely decoded, or just is size returned.
+ * @return The decoded bitmap, or null if the image data could not be
+ * decoded, or, if opts is non-null, if opts requested only the
+ * size be returned (in opts.outWidth and opts.outHeight)
+ */
+ public static Bitmap decodeResource(Resources res, int id, Options opts) {
+ Bitmap bm = null;
+
+ try {
+ InputStream is = res.openRawResource(id);
+ bm = decodeStream(is, null, opts);
+ is.close();
+ }
+ catch (java.io.IOException e) {
+ /* do nothing.
+ If the exception happened on open, bm will be null.
+ If it happened on close, bm is still valid.
+ */
+ }
+ return bm;
+ }
+
+ /**
+ * Decode an image referenced by a resource ID.
+ *
+ * @param res The resources object containing the image data
+ * @param id The resource id of the image data
+ * @return The decoded bitmap, or null if the image could not be decode.
+ */
+ public static Bitmap decodeResource(Resources res, int id) {
+ return decodeResource(res, id, null);
+ }
+
+ /**
+ * Decode an immutable bitmap from the specified byte array.
+ *
+ * @param data byte array of compressed image data
+ * @param offset offset into imageData for where the decoder should begin
+ * parsing.
+ * @param length the number of bytes, beginning at offset, to parse
+ * @param opts null-ok; Options that control downsampling and whether the
+ * image should be completely decoded, or just is size returned.
+ * @return The decoded bitmap, or null if the image data could not be
+ * decoded, or, if opts is non-null, if opts requested only the
+ * size be returned (in opts.outWidth and opts.outHeight)
+ */
+ public static Bitmap decodeByteArray(byte[] data, int offset, int length,
+ Options opts) {
+ if ((offset | length) < 0 || data.length < offset + length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return nativeDecodeByteArray(data, offset, length, opts);
+ }
+
+ /**
+ * Decode an immutable bitmap from the specified byte array.
+ *
+ * @param data byte array of compressed image data
+ * @param offset offset into imageData for where the decoder should begin
+ * parsing.
+ * @param length the number of bytes, beginning at offset, to parse
+ * @return The decoded bitmap, or null if the image could not be decode.
+ */
+ public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
+ return decodeByteArray(data, offset, length, null);
+ }
+
+ /**
+ * Decode an input stream into a bitmap. If the input stream is null, or
+ * cannot be used to decode a bitmap, the function returns null.
+ * The stream's position will be where ever it was after the encoded data
+ * was read.
+ *
+ * @param is The input stream that holds the raw data to be decoded into a
+ * bitmap.
+ * @param outPadding If not null, return the padding rect for the bitmap if
+ * it exists, otherwise set padding to [-1,-1,-1,-1]. If
+ * no bitmap is returned (null) then padding is
+ * unchanged.
+ * @param opts null-ok; Options that control downsampling and whether the
+ * image should be completely decoded, or just is size returned.
+ * @return The decoded bitmap, or null if the image data could not be
+ * decoded, or, if opts is non-null, if opts requested only the
+ * size be returned (in opts.outWidth and opts.outHeight)
+ */
+ public static Bitmap decodeStream(InputStream is, Rect outPadding,
+ Options opts) {
+ // we don't throw in this case, thus allowing the caller to only check
+ // the cache, and not force the image to be decoded.
+ if (is == null) {
+ return null;
+ }
+
+ // we need mark/reset to work properly
+
+ if (!is.markSupported()) {
+ is = new BufferedInputStream(is, 16 * 1024);
+ }
+
+ // so we can call reset() if a given codec gives up after reading up to
+ // this many bytes. FIXME: need to find out from the codecs what this
+ // value should be.
+ is.mark(1024);
+
+ Bitmap bm;
+
+ if (is instanceof AssetManager.AssetInputStream) {
+ bm = nativeDecodeAsset(
+ ((AssetManager.AssetInputStream)is).getAssetInt(), outPadding,
+ opts);
+ }
+ else {
+ // pass some temp storage down to the native code. 1024 is made up,
+ // but should be large enough to avoid too many small calls back
+ // into is.read(...) This number is not related to the value passed
+ // to mark(...) above.
+ byte [] tempStorage = null;
+ if (opts != null)
+ tempStorage = opts.inTempStorage;
+ if (tempStorage == null)
+ tempStorage = new byte[16 * 1024];
+ bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+ }
+
+ try {
+ is.reset();
+ } catch (IOException ex) {
+ // ignore
+ }
+ return bm;
+ }
+
+ /**
+ * Decode an input stream into a bitmap. If the input stream is null, or
+ * cannot be used to decode a bitmap, the function returns null.
+ * The stream's position will be where ever it was after the encoded data
+ * was read.
+ *
+ * @param is The input stream that holds the raw data to be decoded into a
+ * bitmap.
+ * @return The decoded bitmap, or null if the image data could not be
+ * decoded, or, if opts is non-null, if opts requested only the
+ * size be returned (in opts.outWidth and opts.outHeight)
+ */
+ public static Bitmap decodeStream(InputStream is) {
+ return decodeStream(is, null, null);
+ }
+
+ /**
+ * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
+ * return null. The position within the descriptor will not be changed when
+ * this returns, so the descriptor can be used again as is.
+ *
+ * @param fd The file descriptor containing the bitmap data to decode
+ * @param outPadding If not null, return the padding rect for the bitmap if
+ * it exists, otherwise set padding to [-1,-1,-1,-1]. If
+ * no bitmap is returned (null) then padding is
+ * unchanged.
+ * @param opts null-ok; Options that control downsampling and whether the
+ * image should be completely decoded, or just is size returned.
+ * @return the decoded bitmap, or null
+ */
+ public static Bitmap decodeFileDescriptor(FileDescriptor fd,
+ Rect outPadding, Options opts) {
+ return nativeDecodeFileDescriptor(fd, outPadding, opts);
+ }
+
+ /**
+ * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
+ * return null. The position within the descriptor will not be changed when
+ * this returns, so the descriptor can be used again as is.
+ *
+ * @param fd The file descriptor containing the bitmap data to decode
+ * @return the decoded bitmap, or null
+ */
+ public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
+ return nativeDecodeFileDescriptor(fd, null, null);
+ }
+
+ private static native Bitmap nativeDecodeStream(InputStream is,
+ byte[] storage, Rect padding, Options opts);
+ private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
+ Rect padding, Options opts);
+ private static native Bitmap nativeDecodeAsset(int asset, Rect padding,
+ Options opts);
+ private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
+ int length, Options opts);
+}
+
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
new file mode 100644
index 0000000..612b0ab
--- /dev/null
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class BitmapShader extends Shader {
+
+ // we hold on just for the GC, since our native counterpart is using it
+ private Bitmap mBitmap;
+
+ /**
+ * Call this to create a new shader that will draw with a bitmap.
+ *
+ * @param bitmap The bitmap to use inside the shader
+ * @param tileX The tiling mode for x to draw the bitmap in.
+ * @param tileY The tiling mode for y to draw the bitmap in.
+ */
+ public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
+ mBitmap = bitmap;
+ native_instance = nativeCreate(bitmap.ni(),
+ tileX.nativeInt, tileY.nativeInt);
+ }
+
+ private static native int nativeCreate(int native_bitmap,
+ int shaderTileModeX,
+ int shaderTileModeY);
+}
+
diff --git a/graphics/java/android/graphics/BlurMaskFilter.java b/graphics/java/android/graphics/BlurMaskFilter.java
new file mode 100644
index 0000000..dbf57ac
--- /dev/null
+++ b/graphics/java/android/graphics/BlurMaskFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class BlurMaskFilter extends MaskFilter {
+
+ public enum Blur {
+ NORMAL(0), //!< fuzzy inside and outside
+ SOLID(1), //!< solid inside, fuzzy outside
+ OUTER(2), //!< nothing inside, fuzzy outside
+ INNER(3); //!< fuzzy inside, nothing outside
+
+ Blur(int value) {
+ native_int = value;
+ }
+ final int native_int;
+ }
+
+ /**
+ * Create a blur maskfilter.
+ *
+ * @param radius The radius to extend the blur from the original mask. Must be > 0.
+ * @param style The Blur to use
+ * @return The new blur maskfilter
+ */
+ public BlurMaskFilter(float radius, Blur style) {
+ native_instance = nativeConstructor(radius, style.native_int);
+ }
+
+ private static native int nativeConstructor(float radius, int style);
+}
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
new file mode 100644
index 0000000..530655f
--- /dev/null
+++ b/graphics/java/android/graphics/Camera.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 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;
+
+
+public class Camera {
+
+ public Camera() {
+ nativeConstructor();
+ }
+
+ public native void save();
+ public native void restore();
+
+ public native void translate(float x, float y, float z);
+ public native void rotateX(float deg);
+ public native void rotateY(float deg);
+ public native void rotateZ(float deg);
+
+ public void getMatrix(Matrix matrix) {
+ nativeGetMatrix(matrix.native_instance);
+ }
+ public void applyToCanvas(Canvas canvas) {
+ nativeApplyToCanvas(canvas.mNativeCanvas);
+ }
+
+ public native float dotWithNormal(float dx, float dy, float dz);
+
+ protected void finalize() throws Throwable {
+ nativeDestructor();
+ }
+
+ private native void nativeConstructor();
+ private native void nativeDestructor();
+ private native void nativeGetMatrix(int native_matrix);
+ private native void nativeApplyToCanvas(int native_canvas);
+
+ int native_instance;
+}
+
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
new file mode 100644
index 0000000..b57f428
--- /dev/null
+++ b/graphics/java/android/graphics/Canvas.java
@@ -0,0 +1,1468 @@
+/*
+ * Copyright (C) 2006 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 android.text.TextUtils;
+import android.text.SpannedString;
+import android.text.SpannableString;
+import android.text.GraphicsOperations;
+
+import javax.microedition.khronos.opengles.GL;
+
+/**
+ * The Canvas class holds the "draw" calls. To draw something, you need
+ * 4 basic components: A Bitmap to hold the pixels, a Canvas to host
+ * the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect,
+ * Path, text, Bitmap), and a paint (to describe the colors and styles for the
+ * drawing).
+ */
+public class Canvas {
+ // assigned in constructors, freed in finalizer
+ final int mNativeCanvas;
+
+ /* Our native canvas can be either a raster, gl, or picture canvas.
+ If we are raster, then mGL will be null, and mBitmap may or may not be
+ present (our default constructor creates a raster canvas but no
+ java-bitmap is). If we are a gl-based, then mBitmap will be null, and
+ mGL will not be null. Thus both cannot be non-null, but its possible
+ for both to be null.
+ */
+ private Bitmap mBitmap; // if not null, mGL must be null
+ private GL mGL; // if not null, mBitmap must be null
+
+ // optional field set by the caller
+ private DrawFilter mDrawFilter;
+
+ // Used by native code
+ @SuppressWarnings({"UnusedDeclaration"})
+ private int mSurfaceFormat;
+
+ /**
+ * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
+ * draw into.
+ */
+ public Canvas() {
+ // 0 means no native bitmap
+ mNativeCanvas = initRaster(0);
+ }
+
+ /**
+ * Construct a canvas with the specified bitmap to draw into. The bitmap
+ * must be mutable.
+ *
+ * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
+ */
+ public Canvas(Bitmap bitmap) {
+ if (!bitmap.isMutable()) {
+ throw new IllegalStateException(
+ "Immutable bitmap passed to Canvas constructor");
+ }
+ throwIfRecycled(bitmap);
+ mNativeCanvas = initRaster(bitmap.ni());
+ mBitmap = bitmap;
+ }
+
+ /*package*/ Canvas(int nativeCanvas) {
+ if (nativeCanvas == 0) {
+ throw new IllegalStateException();
+ }
+ mNativeCanvas = nativeCanvas;
+ }
+
+ /**
+ * Construct a canvas with the specified gl context. All drawing through
+ * this canvas will be redirected to OpenGL. Note: some features may not
+ * be supported in this mode (e.g. some GL implementations may not support
+ * antialiasing or certain effects like ColorMatrix or certain Xfermodes).
+ * However, no exception will be thrown in those cases.
+ */
+ public Canvas(GL gl) {
+ mNativeCanvas = initGL();
+ mGL = gl;
+ }
+
+ /**
+ * Return the GL object associated with this canvas, or null if it is not
+ * backed by GL.
+ */
+ public GL getGL() {
+ return mGL;
+ }
+
+ /**
+ * Call this to free up OpenGL resources that may be cached or allocated
+ * on behalf of the Canvas. Any subsequent drawing with a GL-backed Canvas
+ * will have to recreate those resources.
+ */
+ public static native void freeGlCaches();
+
+ /**
+ * Specify a bitmap for the canvas to draw into.
+ *
+ * @param bitmap Specifies a mutable bitmap for the canvas to draw into.
+ */
+ public void setBitmap(Bitmap bitmap) {
+ if (!bitmap.isMutable()) {
+ throw new IllegalStateException();
+ }
+ if (mGL != null) {
+ throw new RuntimeException("Can't set a bitmap device on a GL canvas");
+ }
+ throwIfRecycled(bitmap);
+
+ native_setBitmap(mNativeCanvas, bitmap.ni());
+ mBitmap = bitmap;
+ }
+
+ /**
+ * Set the viewport dimensions if this canvas is GL based. If it is not,
+ * this method is ignored and no exception is thrown.
+ *
+ * @param width The width of the viewport
+ * @param height The height of the viewport
+ */
+ public void setViewport(int width, int height) {
+ if (mGL != null) {
+ nativeSetViewport(mNativeCanvas, width, height);
+ }
+ }
+
+ /**
+ * Return true if the device that the current layer draws into is opaque
+ * (i.e. does not support per-pixel alpha).
+ *
+ * @return true if the device that the current layer draws into is opaque
+ */
+ public native boolean isOpaque();
+
+ /**
+ * Returns the width of the current drawing layer
+ *
+ * @return the width of the current drawing layer
+ */
+ public native int getWidth();
+
+ /**
+ * Returns the height of the current drawing layer
+ *
+ * @return the height of the current drawing layer
+ */
+ public native int getHeight();
+
+ // the SAVE_FLAG constants must match their native equivalents
+
+ /** restore the current matrix when restore() is called */
+ public static final int MATRIX_SAVE_FLAG = 0x01;
+ /** restore the current clip when restore() is called */
+ public static final int CLIP_SAVE_FLAG = 0x02;
+ /** the layer needs to per-pixel alpha */
+ public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;
+ /** the layer needs to 8-bits per color component */
+ public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;
+ /** clip against the layer's bounds */
+ public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
+ /** restore everything when restore() is called */
+ public static final int ALL_SAVE_FLAG = 0x1F;
+
+ /**
+ * Saves the current matrix and clip onto a private stack. Subsequent
+ * calls to translate,scale,rotate,skew,concat or clipRect,clipPath
+ * will all operate as usual, but when the balancing call to restore()
+ * is made, those calls will be forgotten, and the settings that existed
+ * before the save() will be reinstated.
+ *
+ * @return The value to pass to restoreToCount() to balance this save()
+ */
+ public native int save();
+
+ /**
+ * Based on saveFlags, can save the current matrix and clip onto a private
+ * stack. Subsequent calls to translate,scale,rotate,skew,concat or
+ * clipRect,clipPath will all operate as usual, but when the balancing
+ * call to restore() is made, those calls will be forgotten, and the
+ * settings that existed before the save() will be reinstated.
+ *
+ * @param saveFlags flag bits that specify which parts of the Canvas state
+ * to save/restore
+ * @return The value to pass to restoreToCount() to balance this save()
+ */
+ public native int save(int saveFlags);
+
+ /**
+ * This behaves the same as save(), but in addition it allocates an
+ * offscreen bitmap. All drawing calls are directed there, and only when
+ * the balancing call to restore() is made is that offscreen transfered to
+ * the canvas (or the previous layer). Subsequent calls to translate,
+ * scale, rotate, skew, concat or clipRect, clipPath all operate on this
+ * copy. When the balancing call to restore() is made, this copy is
+ * deleted and the previous matrix/clip state is restored.
+ *
+ * @param bounds May be null. The maximum size the offscreen bitmap
+ * needs to be (in local coordinates)
+ * @param paint This is copied, and is applied to the offscreen when
+ * restore() is called.
+ * @param saveFlags see _SAVE_FLAG constants
+ * @return value to pass to restoreToCount() to balance this save()
+ */
+ public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
+ return native_saveLayer(mNativeCanvas, bounds,
+ paint != null ? paint.mNativePaint : 0,
+ saveFlags);
+ }
+
+ /**
+ * Helper version of saveLayer() that takes 4 values rather than a RectF.
+ */
+ public int saveLayer(float left, float top, float right, float bottom,
+ Paint paint, int saveFlags) {
+ return native_saveLayer(mNativeCanvas, left, top, right, bottom,
+ paint != null ? paint.mNativePaint : 0,
+ saveFlags);
+ }
+
+ /**
+ * This behaves the same as save(), but in addition it allocates an
+ * offscreen bitmap. All drawing calls are directed there, and only when
+ * the balancing call to restore() is made is that offscreen transfered to
+ * the canvas (or the previous layer). Subsequent calls to translate,
+ * scale, rotate, skew, concat or clipRect, clipPath all operate on this
+ * copy. When the balancing call to restore() is made, this copy is
+ * deleted and the previous matrix/clip state is restored.
+ *
+ * @param bounds The maximum size the offscreen bitmap needs to be
+ * (in local coordinates)
+ * @param alpha The alpha to apply to the offscreen when when it is
+ drawn during restore()
+ * @param saveFlags see _SAVE_FLAG constants
+ * @return value to pass to restoreToCount() to balance this call
+ */
+ public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
+ alpha = Math.min(255, Math.max(0, alpha));
+ return native_saveLayerAlpha(mNativeCanvas, bounds, alpha, saveFlags);
+ }
+
+ /**
+ * Helper for saveLayerAlpha() that takes 4 values instead of a RectF.
+ */
+ public int saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, int saveFlags) {
+ return native_saveLayerAlpha(mNativeCanvas, left, top, right, bottom,
+ alpha, saveFlags);
+ }
+
+ /**
+ * This call balances a previous call to save(), and is used to remove all
+ * modifications to the matrix/clip state since the last save call. It is
+ * an error to call restore() more times than save() was called.
+ */
+ public native void restore();
+
+ /**
+ * Returns the number of matrix/clip states on the Canvas' private stack.
+ * This will equal # save() calls - # restore() calls.
+ */
+ public native int getSaveCount();
+
+ /**
+ * Efficient way to pop any calls to save() that happened after the save
+ * count reached saveCount. It is an error for saveCount to be less than 1.
+ *
+ * Example:
+ * int count = canvas.save();
+ * ... // more calls potentially to save()
+ * canvas.restoreToCount(count);
+ * // now the canvas is back in the same state it was before the initial
+ * // call to save().
+ *
+ * @param saveCount The save level to restore to.
+ */
+ public native void restoreToCount(int saveCount);
+
+ /**
+ * Preconcat the current matrix with the specified translation
+ *
+ * @param dx The distance to translate in X
+ * @param dy The distance to translate in Y
+ */
+ public native void translate(float dx, float dy);
+
+ /**
+ * Preconcat the current matrix with the specified scale.
+ *
+ * @param sx The amount to scale in X
+ * @param sy The amount to scale in Y
+ */
+ public native void scale(float sx, float sy);
+
+ /**
+ * Preconcat the current matrix with the specified scale.
+ *
+ * @param sx The amount to scale in X
+ * @param sy The amount to scale in Y
+ * @param px The x-coord for the pivot point (unchanged by the rotation)
+ * @param py The y-coord for the pivot point (unchanged by the rotation)
+ */
+ public final void scale(float sx, float sy, float px, float py) {
+ translate(px, py);
+ scale(sx, sy);
+ translate(-px, -py);
+ }
+
+ /**
+ * Preconcat the current matrix with the specified rotation.
+ *
+ * @param degrees The amount to rotate, in degrees
+ */
+ public native void rotate(float degrees);
+
+ /**
+ * Preconcat the current matrix with the specified rotation.
+ *
+ * @param degrees The amount to rotate, in degrees
+ * @param px The x-coord for the pivot point (unchanged by the rotation)
+ * @param py The y-coord for the pivot point (unchanged by the rotation)
+ */
+ public final void rotate(float degrees, float px, float py) {
+ translate(px, py);
+ rotate(degrees);
+ translate(-px, -py);
+ }
+
+ /**
+ * Preconcat the current matrix with the specified skew.
+ *
+ * @param sx The amount to skew in X
+ * @param sy The amount to skew in Y
+ */
+ public native void skew(float sx, float sy);
+
+ /**
+ * Preconcat the current matrix with the specified matrix.
+ *
+ * @param matrix The matrix to preconcatenate with the current matrix
+ */
+ public void concat(Matrix matrix) {
+ native_concat(mNativeCanvas, matrix.native_instance);
+ }
+
+ /**
+ * Completely replace the current matrix with the specified matrix. If the
+ * matrix parameter is null, then the current matrix is reset to identity.
+ *
+ * @param matrix The matrix to replace the current matrix with. If it is
+ * null, set the current matrix to identity.
+ */
+ public void setMatrix(Matrix matrix) {
+ native_setMatrix(mNativeCanvas,
+ matrix == null ? 0 : matrix.native_instance);
+ }
+
+ /**
+ * Return, in ctm, the current transformation matrix. This does not alter
+ * the matrix in the canvas, but just returns a copy of it.
+ */
+ public void getMatrix(Matrix ctm) {
+ native_getCTM(mNativeCanvas, ctm.native_instance);
+ }
+
+ /**
+ * Return a new matrix with a copy of the canvas' current transformation
+ * matrix.
+ */
+ public final Matrix getMatrix() {
+ Matrix m = new Matrix();
+ getMatrix(m);
+ return m;
+ }
+
+ /**
+ * Modify the current clip with the specified rectangle.
+ *
+ * @param rect The rect to intersect with the current clip
+ * @param op How the clip is modified
+ * @return true if the resulting clip is non-empty
+ */
+ public boolean clipRect(RectF rect, Region.Op op) {
+ return native_clipRect(mNativeCanvas,
+ rect.left, rect.top, rect.right, rect.bottom,
+ op.nativeInt);
+ }
+
+ /**
+ * Modify the current clip with the specified rectangle, which is
+ * expressed in local coordinates.
+ *
+ * @param rect The rectangle to intersect with the current clip.
+ * @param op How the clip is modified
+ * @return true if the resulting clip is non-empty
+ */
+ public boolean clipRect(Rect rect, Region.Op op) {
+ return native_clipRect(mNativeCanvas,
+ rect.left, rect.top, rect.right, rect.bottom,
+ op.nativeInt);
+ }
+
+ /**
+ * Intersect the current clip with the specified rectangle, which is
+ * expressed in local coordinates.
+ *
+ * @param rect The rectangle to intersect with the current clip.
+ * @return true if the resulting clip is non-empty
+ */
+ public native boolean clipRect(RectF rect);
+
+ /**
+ * Intersect the current clip with the specified rectangle, which is
+ * expressed in local coordinates.
+ *
+ * @param rect The rectangle to intersect with the current clip.
+ * @return true if the resulting clip is non-empty
+ */
+ public native boolean clipRect(Rect rect);
+
+ /**
+ * Modify the current clip with the specified rectangle, which is
+ * expressed in local coordinates.
+ *
+ * @param left The left side of the rectangle to intersect with the
+ * current clip
+ * @param top The top of the rectangle to intersect with the current
+ * clip
+ * @param right The right side of the rectangle to intersect with the
+ * current clip
+ * @param bottom The bottom of the rectangle to intersect with the current
+ * clip
+ * @param op How the clip is modified
+ * @return true if the resulting clip is non-empty
+ */
+ public boolean clipRect(float left, float top, float right, float bottom,
+ Region.Op op) {
+ return native_clipRect(mNativeCanvas, left, top, right, bottom,
+ op.nativeInt);
+ }
+
+ /**
+ * Intersect the current clip with the specified rectangle, which is
+ * expressed in local coordinates.
+ *
+ * @param left The left side of the rectangle to intersect with the
+ * current clip
+ * @param top The top of the rectangle to intersect with the current clip
+ * @param right The right side of the rectangle to intersect with the
+ * current clip
+ * @param bottom The bottom of the rectangle to intersect with the current
+ * clip
+ * @return true if the resulting clip is non-empty
+ */
+ public native boolean clipRect(float left, float top,
+ float right, float bottom);
+
+ /**
+ * Intersect the current clip with the specified rectangle, which is
+ * expressed in local coordinates.
+ *
+ * @param left The left side of the rectangle to intersect with the
+ * current clip
+ * @param top The top of the rectangle to intersect with the current clip
+ * @param right The right side of the rectangle to intersect with the
+ * current clip
+ * @param bottom The bottom of the rectangle to intersect with the current
+ * clip
+ * @return true if the resulting clip is non-empty
+ */
+ public native boolean clipRect(int left, int top,
+ int right, int bottom);
+
+ /**
+ * Modify the current clip with the specified path.
+ *
+ * @param path The path to operate on the current clip
+ * @param op How the clip is modified
+ * @return true if the resulting is non-empty
+ */
+ public boolean clipPath(Path path, Region.Op op) {
+ return native_clipPath(mNativeCanvas, path.ni(), op.nativeInt);
+ }
+
+ /**
+ * Intersect the current clip with the specified path.
+ *
+ * @param path The path to intersect with the current clip
+ * @return true if the resulting is non-empty
+ */
+ public boolean clipPath(Path path) {
+ return clipPath(path, Region.Op.INTERSECT);
+ }
+
+ /**
+ * Modify the current clip with the specified region. Note that unlike
+ * clipRect() and clipPath() which transform their arguments by the
+ * current matrix, clipRegion() assumes its argument is already in the
+ * coordinate system of the current layer's bitmap, and so not
+ * transformation is performed.
+ *
+ * @param region The region to operate on the current clip, based on op
+ * @param op How the clip is modified
+ * @return true if the resulting is non-empty
+ */
+ public boolean clipRegion(Region region, Region.Op op) {
+ return native_clipRegion(mNativeCanvas, region.ni(), op.nativeInt);
+ }
+
+ /**
+ * Intersect the current clip with the specified region. Note that unlike
+ * clipRect() and clipPath() which transform their arguments by the
+ * current matrix, clipRegion() assumes its argument is already in the
+ * coordinate system of the current layer's bitmap, and so not
+ * transformation is performed.
+ *
+ * @param region The region to operate on the current clip, based on op
+ * @return true if the resulting is non-empty
+ */
+ public boolean clipRegion(Region region) {
+ return clipRegion(region, Region.Op.INTERSECT);
+ }
+
+ public DrawFilter getDrawFilter() {
+ return mDrawFilter;
+ }
+
+ public void setDrawFilter(DrawFilter filter) {
+ int nativeFilter = 0;
+ if (filter != null) {
+ nativeFilter = filter.mNativeInt;
+ }
+ mDrawFilter = filter;
+ nativeSetDrawFilter(mNativeCanvas, nativeFilter);
+ }
+
+ public enum EdgeType {
+ BW(0), //!< treat edges by just rounding to nearest pixel boundary
+ AA(1); //!< treat edges by rounding-out, since they may be antialiased
+
+ EdgeType(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Return true if the specified rectangle, after being transformed by the
+ * current matrix, would lie completely outside of the current clip. Call
+ * this to check if an area you intend to draw into is clipped out (and
+ * therefore you can skip making the draw calls).
+ *
+ * @param rect the rect to compare with the current clip
+ * @param type specifies how to treat the edges (BW or antialiased)
+ * @return true if the rect (transformed by the canvas' matrix)
+ * does not intersect with the canvas' clip
+ */
+ public boolean quickReject(RectF rect, EdgeType type) {
+ return native_quickReject(mNativeCanvas, rect, type.nativeInt);
+ }
+
+ /**
+ * Return true if the specified path, after being transformed by the
+ * current matrix, would lie completely outside of the current clip. Call
+ * this to check if an area you intend to draw into is clipped out (and
+ * therefore you can skip making the draw calls). Note: for speed it may
+ * return false even if the path itself might not intersect the clip
+ * (i.e. the bounds of the path intersects, but the path does not).
+ *
+ * @param path The path to compare with the current clip
+ * @param type true if the path should be considered antialiased,
+ * since that means it may
+ * affect a larger area (more pixels) than
+ * non-antialiased.
+ * @return true if the path (transformed by the canvas' matrix)
+ * does not intersect with the canvas' clip
+ */
+ public boolean quickReject(Path path, EdgeType type) {
+ return native_quickReject(mNativeCanvas, path.ni(), type.nativeInt);
+ }
+
+ /**
+ * Return true if the specified rectangle, after being transformed by the
+ * current matrix, would lie completely outside of the current clip. Call
+ * this to check if an area you intend to draw into is clipped out (and
+ * therefore you can skip making the draw calls).
+ *
+ * @param left The left side of the rectangle to compare with the
+ * current clip
+ * @param top The top of the rectangle to compare with the current
+ * clip
+ * @param right The right side of the rectangle to compare with the
+ * current clip
+ * @param bottom The bottom of the rectangle to compare with the
+ * current clip
+ * @param type true if the rect should be considered antialiased,
+ * since that means it may affect a larger area (more
+ * pixels) than non-antialiased.
+ * @return true if the rect (transformed by the canvas' matrix)
+ * does not intersect with the canvas' clip
+ */
+ public boolean quickReject(float left, float top, float right, float bottom,
+ EdgeType type) {
+ return native_quickReject(mNativeCanvas, left, top, right, bottom,
+ type.nativeInt);
+ }
+
+ /**
+ * Retrieve the clip bounds, returning true if they are non-empty.
+ *
+ * @param bounds Return the clip bounds here. If it is null, ignore it but
+ * still return true if the current clip is non-empty.
+ * @return true if the current clip is non-empty.
+ */
+ public boolean getClipBounds(Rect bounds) {
+ return native_getClipBounds(mNativeCanvas, bounds);
+ }
+
+ /**
+ * Retrieve the clip bounds.
+ *
+ * @return the clip bounds, or [0, 0, 0, 0] if the clip is empty.
+ */
+ public final Rect getClipBounds() {
+ Rect r = new Rect();
+ getClipBounds(r);
+ return r;
+ }
+
+ /**
+ * Fill the entire canvas' bitmap (restricted to the current clip) with the
+ * specified RGB color, using srcover porterduff mode.
+ *
+ * @param r red component (0..255) of the color to draw onto the canvas
+ * @param g green component (0..255) of the color to draw onto the canvas
+ * @param b blue component (0..255) of the color to draw onto the canvas
+ */
+ public void drawRGB(int r, int g, int b) {
+ native_drawRGB(mNativeCanvas, r, g, b);
+ }
+
+ /**
+ * Fill the entire canvas' bitmap (restricted to the current clip) with the
+ * specified ARGB color, using srcover porterduff mode.
+ *
+ * @param a alpha component (0..255) of the color to draw onto the canvas
+ * @param r red component (0..255) of the color to draw onto the canvas
+ * @param g green component (0..255) of the color to draw onto the canvas
+ * @param b blue component (0..255) of the color to draw onto the canvas
+ */
+ public void drawARGB(int a, int r, int g, int b) {
+ native_drawARGB(mNativeCanvas, a, r, g, b);
+ }
+
+ /**
+ * Fill the entire canvas' bitmap (restricted to the current clip) with the
+ * specified color, using srcover porterduff mode.
+ *
+ * @param color the color to draw onto the canvas
+ */
+ public void drawColor(int color) {
+ native_drawColor(mNativeCanvas, color);
+ }
+
+ /**
+ * Fill the entire canvas' bitmap (restricted to the current clip) with the
+ * specified color and porter-duff xfermode.
+ *
+ * @param color the color to draw with
+ * @param mode the porter-duff mode to apply to the color
+ */
+ public void drawColor(int color, PorterDuff.Mode mode) {
+ native_drawColor(mNativeCanvas, color, mode.nativeInt);
+ }
+
+ /**
+ * Fill the entire canvas' bitmap (restricted to the current clip) with
+ * the specified paint. This is equivalent (but faster) to drawing an
+ * infinitely large rectangle with the specified paint.
+ *
+ * @param paint The paint used to draw onto the canvas
+ */
+ public void drawPaint(Paint paint) {
+ native_drawPaint(mNativeCanvas, paint.mNativePaint);
+ }
+
+ /**
+ * Draw a series of points. Each point is centered at the coordinate
+ * specified by pts[], and its diameter is specified by the paint's stroke
+ * width (as transformed by the canvas' CTM), with special treatment for
+ * a stroke width of 0, which always draws exactly 1 pixel (or at most 4
+ * if antialiasing is enabled). The shape of the point is controlled by
+ * the paint's Cap type. The shape is a square, unless the cap type is
+ * Round, in which case the shape is a circle.
+ *
+ * @param pts Array of points to draw [x0 y0 x1 y1 x2 y2 ...]
+ * @param offset Number of values to skip before starting to draw.
+ * @param count The number of values to process, after skipping offset
+ * of them. Since one point uses two values, the number of
+ * "points" that are drawn is really (count >> 1).
+ * @param paint The paint used to draw the points
+ */
+ public native void drawPoints(float[] pts, int offset, int count,
+ Paint paint);
+
+ /**
+ * Helper for drawPoints() that assumes you want to draw the entire array
+ */
+ public void drawPoints(float[] pts, Paint paint) {
+ drawPoints(pts, 0, pts.length, paint);
+ }
+
+ /**
+ * Helper for drawPoints() for drawing a single point.
+ */
+ public native void drawPoint(float x, float y, Paint paint);
+
+ /**
+ * Draw a line segment with the specified start and stop x,y coordinates,
+ * using the specified paint. NOTE: since a line is always "framed", the
+ * Style is ignored in the paint.
+ *
+ * @param startX The x-coordinate of the start point of the line
+ * @param startY The y-coordinate of the start point of the line
+ * @param paint The paint used to draw the line
+ */
+ public void drawLine(float startX, float startY, float stopX, float stopY,
+ Paint paint) {
+ native_drawLine(mNativeCanvas, startX, startY, stopX, stopY,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw a series of lines. Each line is taken from 4 consecutive values
+ * in the pts array. Thus to draw 1 line, the array must contain at least 4
+ * values. This is logically the same as drawing the array as follows:
+ * drawLine(pts[0], pts[1], pts[2], pts[3]) followed by
+ * drawLine(pts[4], pts[5], pts[6], pts[7]) and so on.
+ *
+ * @param pts Array of points to draw [x0 y0 x1 y1 x2 y2 ...]
+ * @param offset Number of values in the array to skip before drawing.
+ * @param count The number of values in the array to process, after
+ * skipping "offset" of them. Since each line uses 4 values,
+ * the number of "lines" that are drawn is really
+ * (count >> 2).
+ * @param paint The paint used to draw the points
+ */
+ public native void drawLines(float[] pts, int offset, int count,
+ Paint paint);
+
+ public void drawLines(float[] pts, Paint paint) {
+ drawLines(pts, 0, pts.length, paint);
+ }
+
+ /**
+ * Draw the specified Rect using the specified paint. The rectangle will
+ * be filled or framed based on the Style in the paint.
+ *
+ * @param rect The rect to be drawn
+ * @param paint The paint used to draw the rect
+ */
+ public void drawRect(RectF rect, Paint paint) {
+ native_drawRect(mNativeCanvas, rect, paint.mNativePaint);
+ }
+
+ /**
+ * Draw the specified Rect using the specified Paint. The rectangle
+ * will be filled or framed based on the Style in the paint.
+ *
+ * @param r The rectangle to be drawn.
+ * @param paint The paint used to draw the rectangle
+ */
+ public void drawRect(Rect r, Paint paint) {
+ drawRect(r.left, r.top, r.right, r.bottom, paint);
+ }
+
+
+ /**
+ * Draw the specified Rect using the specified paint. The rectangle will
+ * be filled or framed based on the Style in the paint.
+ *
+ * @param left The left side of the rectangle to be drawn
+ * @param top The top side of the rectangle to be drawn
+ * @param right The right side of the rectangle to be drawn
+ * @param bottom The bottom side of the rectangle to be drawn
+ * @param paint The paint used to draw the rect
+ */
+ public void drawRect(float left, float top, float right, float bottom,
+ Paint paint) {
+ native_drawRect(mNativeCanvas, left, top, right, bottom,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw the specified oval using the specified paint. The oval will be
+ * filled or framed based on the Style in the paint.
+ *
+ * @param oval The rectangle bounds of the oval to be drawn
+ */
+ public void drawOval(RectF oval, Paint paint) {
+ if (oval == null) {
+ throw new NullPointerException();
+ }
+ native_drawOval(mNativeCanvas, oval, paint.mNativePaint);
+ }
+
+ /**
+ * Draw the specified circle using the specified paint. If radius is <= 0,
+ * then nothing will be drawn. The circle will be filled or framed based
+ * on the Style in the paint.
+ *
+ * @param cx The x-coordinate of the center of the cirle to be drawn
+ * @param cy The y-coordinate of the center of the cirle to be drawn
+ * @param radius The radius of the cirle to be drawn
+ * @param paint The paint used to draw the circle
+ */
+ public void drawCircle(float cx, float cy, float radius, Paint paint) {
+ native_drawCircle(mNativeCanvas, cx, cy, radius,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw the specified arc, which will be scaled to fit inside the
+ * specified oval. If the sweep angle is >= 360, then the oval is drawn
+ * completely. Note that this differs slightly from SkPath::arcTo, which
+ * treats the sweep angle mod 360.
+ *
+ * @param oval The bounds of oval used to define the shape and size
+ * of the arc
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ * @param useCenter If true, include the center of the oval in the arc, and
+ close it if it is being stroked. This will draw a wedge
+ * @param paint The paint used to draw the arc
+ */
+ public void drawArc(RectF oval, float startAngle, float sweepAngle,
+ boolean useCenter, Paint paint) {
+ if (oval == null) {
+ throw new NullPointerException();
+ }
+ native_drawArc(mNativeCanvas, oval, startAngle, sweepAngle,
+ useCenter, paint.mNativePaint);
+ }
+
+ /**
+ * Draw the specified round-rect using the specified paint. The roundrect
+ * will be filled or framed based on the Style in the paint.
+ *
+ * @param rect The rectangular bounds of the roundRect to be drawn
+ * @param rx The x-radius of the oval used to round the corners
+ * @param ry The y-radius of the oval used to round the corners
+ * @param paint The paint used to draw the roundRect
+ */
+ public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
+ if (rect == null) {
+ throw new NullPointerException();
+ }
+ native_drawRoundRect(mNativeCanvas, rect, rx, ry,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw the specified path using the specified paint. The path will be
+ * filled or framed based on the Style in the paint.
+ *
+ * @param path The path to be drawn
+ * @param paint The paint used to draw the path
+ */
+ public void drawPath(Path path, Paint paint) {
+ native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint);
+ }
+
+ private static void throwIfRecycled(Bitmap bitmap) {
+ if (bitmap.isRecycled()) {
+ throw new RuntimeException(
+ "Canvas: trying to use a recycled bitmap " + bitmap);
+ }
+ }
+
+ /**
+ * Draw the specified bitmap, with its top/left corner at (x,y), using
+ * the specified paint, transformed by the current matrix.
+ * Note: if the paint contains a maskfilter that generates a mask which
+ * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
+ * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
+ * Thus the color outside of the original width/height will be the edge
+ * color replicated.
+ *
+ * @param bitmap The bitmap to be drawn
+ * @param left The position of the left side of the bitmap being drawn
+ * @param top The position of the top side of the bitmap being drawn
+ * @param paint The paint used to draw the bitmap (may be null)
+ */
+ public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
+ throwIfRecycled(bitmap);
+ native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
+ paint != null ? paint.mNativePaint : 0);
+ }
+
+ /**
+ * Draw the specified bitmap, scaling/translating automatically to fill
+ * the destination rectangle. If the source rectangle is not null, it
+ * specifies the subset of the bitmap to draw.
+ * Note: if the paint contains a maskfilter that generates a mask which
+ * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
+ * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
+ * Thus the color outside of the original width/height will be the edge
+ * color replicated.
+ *
+ * @param bitmap The bitmap to be drawn
+ * @param src May be null. The subset of the bitmap to be drawn
+ * @param dst The rectangle that the bitmap will be scaled/translated
+ * to fit into
+ * @param paint May be null. The paint used to draw the bitmap
+ */
+ public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
+ if (dst == null) {
+ throw new NullPointerException();
+ }
+ throwIfRecycled(bitmap);
+ native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
+ paint != null ? paint.mNativePaint : 0);
+ }
+
+ /**
+ * Draw the specified bitmap, scaling/translating automatically to fill
+ * the destination rectangle. If the source rectangle is not null, it
+ * specifies the subset of the bitmap to draw.
+ * Note: if the paint contains a maskfilter that generates a mask which
+ * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
+ * then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
+ * Thus the color outside of the original width/height will be the edge
+ * color replicated.
+ *
+ * @param bitmap The bitmap to be drawn
+ * @param src May be null. The subset of the bitmap to be drawn
+ * @param dst The rectangle that the bitmap will be scaled/translated
+ * to fit into
+ * @param paint May be null. The paint used to draw the bitmap
+ */
+ public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
+ if (dst == null) {
+ throw new NullPointerException();
+ }
+ throwIfRecycled(bitmap);
+ native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
+ paint != null ? paint.mNativePaint : 0);
+ }
+
+ /**
+ * Treat the specified array of colors as a bitmap, and draw it. This gives
+ * the same result as first creating a bitmap from the array, and then
+ * drawing it, but this method avoids explicitly creating a bitmap object
+ * which can be more efficient if the colors are changing often.
+ *
+ * @param colors Array of colors representing the pixels of the bitmap
+ * @param offset Offset into the array of colors for the first pixel
+ * @param stride The number of of colors in the array between rows (must be
+ * >= width or <= -width).
+ * @param x The X coordinate for where to draw the bitmap
+ * @param y The Y coordinate for where to draw the bitmap
+ * @param width The width of the bitmap
+ * @param height The height of the bitmap
+ * @param hasAlpha True if the alpha channel of the colors contains valid
+ * values. If false, the alpha byte is ignored (assumed to
+ * be 0xFF for every pixel).
+ * @param paint May be null. The paint used to draw the bitmap
+ */
+ public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
+ int width, int height, boolean hasAlpha,
+ Paint paint) {
+ // check for valid input
+ if (width < 0) {
+ throw new IllegalArgumentException("width must be >= 0");
+ }
+ if (height < 0) {
+ throw new IllegalArgumentException("height must be >= 0");
+ }
+ 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();
+ }
+ // quick escape if there's nothing to draw
+ if (width == 0 || height == 0) {
+ return;
+ }
+ // punch down to native for the actual draw
+ native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y,
+ width, height, hasAlpha,
+ paint != null ? paint.mNativePaint : 0);
+ }
+
+ /**
+ * Draw the bitmap using the specified matrix.
+ *
+ * @param bitmap The bitmap to draw
+ * @param matrix The matrix used to transform the bitmap when it is drawn
+ * @param paint May be null. The paint used to draw the bitmap
+ */
+ public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
+ nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(),
+ paint != null ? paint.mNativePaint : 0);
+ }
+
+ private static void checkRange(int length, int offset, int count) {
+ if ((offset | count) < 0 || offset + count > length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Draw the bitmap through the mesh, where mesh vertices are evenly
+ * distributed across the bitmap. There are meshWidth+1 vertices across, and
+ * meshHeight+1 vertices down. The verts array is accessed in row-major
+ * order, so that the first meshWidth+1 vertices are distributed across the
+ * top of the bitmap from left to right. A more general version of this
+ * methid is drawVertices().
+ *
+ * @param bitmap The bitmap to draw using the mesh
+ * @param meshWidth The number of columns in the mesh. Nothing is drawn if
+ * this is 0
+ * @param meshHeight The number of rows in the mesh. Nothing is drawn if
+ * this is 0
+ * @param verts Array of x,y pairs, specifying where the mesh should be
+ * drawn. There must be at least
+ * (meshWidth+1) * (meshHeight+1) * 2 + meshOffset values
+ * in the array
+ * @param vertOffset Number of verts elements to skip before drawing
+ * @param colors May be null. Specifies a color at each vertex, which is
+ * interpolated across the cell, and whose values are
+ * multiplied by the corresponding bitmap colors. If not null,
+ * there must be at least (meshWidth+1) * (meshHeight+1) +
+ * colorOffset values in the array.
+ * @param colorOffset Number of color elements to skip before drawing
+ * @param paint May be null. The paint used to draw the bitmap
+ */
+ public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight,
+ float[] verts, int vertOffset,
+ int[] colors, int colorOffset, Paint paint) {
+ if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ if (meshWidth == 0 || meshHeight == 0) {
+ return;
+ }
+ int count = (meshWidth + 1) * (meshHeight + 1);
+ // we mul by 2 since we need two floats per vertex
+ checkRange(verts.length, vertOffset, count * 2);
+ if (colors != null) {
+ // no mul by 2, since we need only 1 color per vertex
+ checkRange(colors.length, colorOffset, count);
+ }
+ nativeDrawBitmapMesh(mNativeCanvas, bitmap.ni(), meshWidth, meshHeight,
+ verts, vertOffset, colors, colorOffset,
+ paint != null ? paint.mNativePaint : 0);
+ }
+
+ public enum VertexMode {
+ TRIANGLES(0),
+ TRIANGLE_STRIP(1),
+ TRIANGLE_FAN(2);
+
+ VertexMode(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Draw the array of vertices, interpreted as triangles (based on mode). The
+ * verts array is required, and specifies the x,y pairs for each vertex. If
+ * texs is non-null, then it is used to specify the coordinate in shader
+ * coordinates to use at each vertex (the paint must have a shader in this
+ * case). If there is no texs array, but there is a color array, then each
+ * color is interpolated across its corresponding triangle in a gradient. If
+ * both texs and colors arrays are present, then they behave as before, but
+ * the resulting color at each pixels is the result of multiplying the
+ * colors from the shader and the color-gradient together. The indices array
+ * is optional, but if it is present, then it is used to specify the index
+ * of each triangle, rather than just walking through the arrays in order.
+ *
+ * @param mode How to interpret the array of vertices
+ * @param vertexCount The number of values in the vertices array (and
+ * corresponding texs and colors arrays if non-null). Each logical
+ * vertex is two values (x, y), vertexCount must be a multiple of 2.
+ * @param verts Array of vertices for the mesh
+ * @param vertOffset Number of values in the verts to skip before drawing.
+ * @param texs May be null. If not null, specifies the coordinates to sample
+ * into the current shader (e.g. bitmap tile or gradient)
+ * @param texOffset Number of values in texs to skip before drawing.
+ * @param colors May be null. If not null, specifies a color for each
+ * vertex, to be interpolated across the triangle.
+ * @param colorOffset Number of values in colors to skip before drawing.
+ * @param indices If not null, array of indices to reference into the
+ * vertex (texs, colors) array.
+ * @param indexCount number of entries in the indices array (if not null).
+ * @param paint Specifies the shader to use if the texs array is non-null.
+ */
+ public void drawVertices(VertexMode mode, int vertexCount,
+ float[] verts, int vertOffset,
+ float[] texs, int texOffset,
+ int[] colors, int colorOffset,
+ short[] indices, int indexOffset,
+ int indexCount, Paint paint) {
+ checkRange(verts.length, vertOffset, vertexCount);
+ if (texs != null) {
+ checkRange(texs.length, texOffset, vertexCount);
+ }
+ if (colors != null) {
+ checkRange(colors.length, colorOffset, vertexCount);
+ }
+ if (indices != null) {
+ checkRange(indices.length, indexOffset, indexCount);
+ }
+ nativeDrawVertices(mNativeCanvas, mode.nativeInt, vertexCount, verts,
+ vertOffset, texs, texOffset, colors, colorOffset,
+ indices, indexOffset, indexCount, paint.mNativePaint);
+ }
+
+ /**
+ * Draw the text, with origin at (x,y), using the specified paint. The
+ * origin is interpreted based on the Align setting in the paint.
+ *
+ * @param text The text to be drawn
+ * @param x The x-coordinate of the origin of the text being drawn
+ * @param y The y-coordinate of the origin of the text being drawn
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public void drawText(char[] text, int index, int count, float x, float y,
+ Paint paint) {
+ if ((index | count | (index + count) |
+ (text.length - index - count)) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ native_drawText(mNativeCanvas, text, index, count, x, y,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw the text, with origin at (x,y), using the specified paint. The
+ * origin is interpreted based on the Align setting in the paint.
+ *
+ * @param text The text to be drawn
+ * @param x The x-coordinate of the origin of the text being drawn
+ * @param y The y-coordinate of the origin of the text being drawn
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public native void drawText(String text, float x, float y, Paint paint);
+
+ /**
+ * Draw the text, with origin at (x,y), using the specified paint.
+ * The origin is interpreted based on the Align setting in the paint.
+ *
+ * @param text The text to be drawn
+ * @param start The index of the first character in text to draw
+ * @param end (end - 1) is the index of the last character in text to draw
+ * @param x The x-coordinate of the origin of the text being drawn
+ * @param y The y-coordinate of the origin of the text being drawn
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public void drawText(String text, int start, int end, float x, float y,
+ Paint paint) {
+ if ((start | end | (end - start) | (text.length() - end)) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ native_drawText(mNativeCanvas, text, start, end, x, y,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw the specified range of text, specified by start/end, with its
+ * origin at (x,y), in the specified Paint. The origin is interpreted
+ * based on the Align setting in the Paint.
+ *
+ * @param text The text to be drawn
+ * @param start The index of the first character in text to draw
+ * @param end (end - 1) is the index of the last character in text
+ * to draw
+ * @param x The x-coordinate of origin for where to draw the text
+ * @param y The y-coordinate of origin for where to draw the text
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public void drawText(CharSequence text, int start, int end, float x,
+ float y, Paint paint) {
+ if (text instanceof String || text instanceof SpannedString ||
+ text instanceof SpannableString) {
+ native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
+ paint.mNativePaint);
+ }
+ else if (text instanceof GraphicsOperations) {
+ ((GraphicsOperations) text).drawText(this, start, end, x, y,
+ paint);
+ }
+ else {
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ TextUtils.getChars(text, start, end, buf, 0);
+ drawText(buf, 0, end - start, x, y, paint);
+ TemporaryBuffer.recycle(buf);
+ }
+ }
+
+ /**
+ * Draw the text in the array, with each character's origin specified by
+ * the pos array.
+ *
+ * @param text The text to be drawn
+ * @param index The index of the first character to draw
+ * @param count The number of characters to draw, starting from index.
+ * @param pos Array of [x,y] positions, used to position each
+ * character
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public void drawPosText(char[] text, int index, int count, float[] pos,
+ Paint paint) {
+ if (index < 0 || index + count > text.length || count*2 > pos.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ native_drawPosText(mNativeCanvas, text, index, count, pos,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw the text in the array, with each character's origin specified by
+ * the pos array.
+ *
+ * @param text The text to be drawn
+ * @param pos Array of [x,y] positions, used to position each character
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public void drawPosText(String text, float[] pos, Paint paint) {
+ if (text.length()*2 > pos.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_drawPosText(mNativeCanvas, text, pos, paint.mNativePaint);
+ }
+
+ /**
+ * Draw the text, with origin at (x,y), using the specified paint, along
+ * the specified path. The paint's Align setting determins where along the
+ * path to start the text.
+ *
+ * @param text The text to be drawn
+ * @param path The path the text should follow for its baseline
+ * @param hOffset The distance along the path to add to the text's
+ * starting position
+ * @param vOffset The distance above(-) or below(+) the path to position
+ * the text
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public void drawTextOnPath(char[] text, int index, int count, Path path,
+ float hOffset, float vOffset, Paint paint) {
+ if (index < 0 || index + count > text.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_drawTextOnPath(mNativeCanvas, text, index, count,
+ path.ni(), hOffset, vOffset,
+ paint.mNativePaint);
+ }
+
+ /**
+ * Draw the text, with origin at (x,y), using the specified paint, along
+ * the specified path. The paint's Align setting determins where along the
+ * path to start the text.
+ *
+ * @param text The text to be drawn
+ * @param path The path the text should follow for its baseline
+ * @param hOffset The distance along the path to add to the text's
+ * starting position
+ * @param vOffset The distance above(-) or below(+) the path to position
+ * the text
+ * @param paint The paint used for the text (e.g. color, size, style)
+ */
+ public void drawTextOnPath(String text, Path path, float hOffset,
+ float vOffset, Paint paint) {
+ if (text.length() > 0) {
+ native_drawTextOnPath(mNativeCanvas, text, path.ni(),
+ hOffset, vOffset, paint.mNativePaint);
+ }
+ }
+
+ /**
+ * Save the canvas state, draw the picture, and restore the canvas state.
+ * This differs from picture.draw(canvas), which does not perform any
+ * save/restore.
+ *
+ * @param picture The picture to be drawn
+ */
+ public void drawPicture(Picture picture) {
+ picture.endRecording();
+ native_drawPicture(mNativeCanvas, picture.ni());
+ }
+
+ /**
+ * Draw the picture, stretched to fit into the dst rectangle.
+ */
+ public void drawPicture(Picture picture, RectF dst) {
+ save();
+ translate(dst.left, dst.top);
+ if (picture.getWidth() > 0 && picture.getHeight() > 0) {
+ scale(dst.width() / picture.getWidth(),
+ dst.height() / picture.getHeight());
+ }
+ drawPicture(picture);
+ restore();
+ }
+
+ /**
+ * Draw the picture, stretched to fit into the dst rectangle.
+ */
+ public void drawPicture(Picture picture, Rect dst) {
+ save();
+ translate(dst.left, dst.top);
+ if (picture.getWidth() > 0 && picture.getHeight() > 0) {
+ scale((float)dst.width() / picture.getWidth(),
+ (float)dst.height() / picture.getHeight());
+ }
+ drawPicture(picture);
+ restore();
+ }
+
+ protected void finalize() throws Throwable {
+ super.finalize();
+ finalizer(mNativeCanvas);
+ }
+
+ private static native int initRaster(int nativeBitmapOrZero);
+ private static native int initGL();
+ private static native void native_setBitmap(int nativeCanvas, int bitmap);
+ private static native void nativeSetViewport(int nCanvas, int w, int h);
+ private static native int native_saveLayer(int nativeCanvas, RectF bounds,
+ int paint, int layerFlags);
+ private static native int native_saveLayer(int nativeCanvas, float l,
+ float t, float r, float b,
+ int paint, int layerFlags);
+ private static native int native_saveLayerAlpha(int nativeCanvas,
+ RectF bounds, int alpha,
+ int layerFlags);
+ private static native int native_saveLayerAlpha(int nativeCanvas, float l,
+ float t, float r, float b,
+ int alpha, int layerFlags);
+
+ private static native void native_concat(int nCanvas, int nMatrix);
+ private static native void native_setMatrix(int nCanvas, int nMatrix);
+ private static native boolean native_clipRect(int nCanvas,
+ float left, float top,
+ float right, float bottom,
+ int regionOp);
+ private static native boolean native_clipPath(int nativeCanvas,
+ int nativePath,
+ int regionOp);
+ private static native boolean native_clipRegion(int nativeCanvas,
+ int nativeRegion,
+ int regionOp);
+ private static native void nativeSetDrawFilter(int nativeCanvas,
+ int nativeFilter);
+ private static native boolean native_getClipBounds(int nativeCanvas,
+ Rect bounds);
+ private static native void native_getCTM(int canvas, int matrix);
+ private static native boolean native_quickReject(int nativeCanvas,
+ RectF rect,
+ int native_edgeType);
+ private static native boolean native_quickReject(int nativeCanvas,
+ int path,
+ int native_edgeType);
+ private static native boolean native_quickReject(int nativeCanvas,
+ float left, float top,
+ float right, float bottom,
+ int native_edgeType);
+ private static native void native_drawRGB(int nativeCanvas, int r, int g,
+ int b);
+ private static native void native_drawARGB(int nativeCanvas, int a, int r,
+ int g, int b);
+ private static native void native_drawColor(int nativeCanvas, int color);
+ private static native void native_drawColor(int nativeCanvas, int color,
+ int mode);
+ private static native void native_drawPaint(int nativeCanvas, int paint);
+ private static native void native_drawLine(int nativeCanvas, float startX,
+ float startY, float stopX,
+ float stopY, int paint);
+ private static native void native_drawRect(int nativeCanvas, RectF rect,
+ int paint);
+ private static native void native_drawRect(int nativeCanvas, float left,
+ float top, float right,
+ float bottom, int paint);
+ private static native void native_drawOval(int nativeCanvas, RectF oval,
+ int paint);
+ private static native void native_drawCircle(int nativeCanvas, float cx,
+ float cy, float radius,
+ int paint);
+ private static native void native_drawArc(int nativeCanvas, RectF oval,
+ float startAngle, float sweep,
+ boolean useCenter, int paint);
+ private static native void native_drawRoundRect(int nativeCanvas,
+ RectF rect, float rx,
+ float ry, int paint);
+ private static native void native_drawPath(int nativeCanvas, int path,
+ int paint);
+ private static native void native_drawBitmap(int nativeCanvas, int bitmap,
+ float left, float top,
+ int nativePaintOrZero);
+ private static native void native_drawBitmap(int nativeCanvas, int bitmap,
+ Rect src, RectF dst,
+ int nativePaintOrZero);
+ private static native void native_drawBitmap(int nativeCanvas, int bitmap,
+ Rect src, Rect dst,
+ int nativePaintOrZero);
+ private static native void native_drawBitmap(int nativeCanvas, int[] colors,
+ int offset, int stride, int x,
+ int y, int width, int height,
+ boolean hasAlpha,
+ int nativePaintOrZero);
+ private static native void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
+ int nMatrix, int nPaint);
+ private static native void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
+ int meshWidth, int meshHeight, float[] verts, int vertOffset,
+ int[] colors, int colorOffset, int nPaint);
+ private static native void nativeDrawVertices(int nCanvas, int mode, int n,
+ float[] verts, int vertOffset, float[] texs, int texOffset,
+ int[] colors, int colorOffset, short[] indices,
+ int indexOffset, int indexCount, int nPaint);
+
+ private static native void native_drawText(int nativeCanvas, char[] text,
+ int index, int count, float x,
+ float y, int paint);
+ private static native void native_drawText(int nativeCanvas, String text,
+ int start, int end, float x,
+ float y, int paint);
+ private static native void native_drawPosText(int nativeCanvas,
+ char[] text, int index,
+ int count, float[] pos,
+ int paint);
+ private static native void native_drawPosText(int nativeCanvas,
+ String text, float[] pos,
+ int paint);
+ private static native void native_drawTextOnPath(int nativeCanvas,
+ char[] text, int index,
+ int count, int path,
+ float hOffset,
+ float vOffset, int paint);
+ private static native void native_drawTextOnPath(int nativeCanvas,
+ String text, int path,
+ float hOffset,
+ float vOffset, int paint);
+ private static native void native_drawPicture(int nativeCanvas,
+ int nativePicture);
+ private static native void finalizer(int nativeCanvas);
+}
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
new file mode 100644
index 0000000..3fc391c
--- /dev/null
+++ b/graphics/java/android/graphics/Color.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2006 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.util.HashMap;
+import java.util.Locale;
+
+/**
+ * The Color class defines methods for creating and converting color ints.
+ * Colors are represented as packed ints, made up of 4 bytes: alpha, red,
+ * green, blue. The values are unpremultiplied, meaning any transparency is
+ * stored solely in the alpha component, and not in the color components. The
+ * components are stored as follows (alpha << 24) | (red << 16) |
+ * (green << 8) | blue. Each component ranges between 0..255 with 0
+ * meaning no contribution for that component, and 255 meaning 100%
+ * contribution. Thus opaque-black would be 0xFF000000 (100% opaque but
+ * no contributes from red, gree, blue, and opaque-white would be 0xFFFFFFFF
+ */
+public class Color {
+ public static final int BLACK = 0xFF000000;
+ public static final int DKGRAY = 0xFF444444;
+ public static final int GRAY = 0xFF888888;
+ public static final int LTGRAY = 0xFFCCCCCC;
+ public static final int WHITE = 0xFFFFFFFF;
+ public static final int RED = 0xFFFF0000;
+ public static final int GREEN = 0xFF00FF00;
+ public static final int BLUE = 0xFF0000FF;
+ public static final int YELLOW = 0xFFFFFF00;
+ public static final int CYAN = 0xFF00FFFF;
+ public static final int MAGENTA = 0xFFFF00FF;
+ public static final int TRANSPARENT = 0;
+
+ /**
+ * Return the alpha component of a color int. This is the same as saying
+ * color >>> 24
+ */
+ public static int alpha(int color) {
+ return color >>> 24;
+ }
+
+ /**
+ * Return the red component of a color int. This is the same as saying
+ * (color >> 16) & 0xFF
+ */
+ public static int red(int color) {
+ return (color >> 16) & 0xFF;
+ }
+
+ /**
+ * Return the green component of a color int. This is the same as saying
+ * (color >> 8) & 0xFF
+ */
+ public static int green(int color) {
+ return (color >> 8) & 0xFF;
+ }
+
+ /**
+ * Return the blue component of a color int. This is the same as saying
+ * color & 0xFF
+ */
+ public static int blue(int color) {
+ return color & 0xFF;
+ }
+
+ /**
+ * Return a color-int from red, green, blue components.
+ * The alpha component is implicity 255 (fully opaque).
+ * These component values should be [0..255], but there is no
+ * range check performed, so if they are out of range, the
+ * returned color is undefined.
+ * @param red Red component [0..255] of the color
+ * @param green Green component [0..255] of the color
+ * @param blue Blue component [0..255] of the color
+ */
+ public static int rgb(int red, int green, int blue) {
+ return (0xFF << 24) | (red << 16) | (green << 8) | blue;
+ }
+
+ /**
+ * Return a color-int from alpha, red, green, blue components.
+ * These component values should be [0..255], but there is no
+ * range check performed, so if they are out of range, the
+ * returned color is undefined.
+ * @param alpha Alpha component [0..255] of the color
+ * @param red Red component [0..255] of the color
+ * @param green Green component [0..255] of the color
+ * @param blue Blue component [0..255] of the color
+ */
+ public static int argb(int alpha, int red, int green, int blue) {
+ return (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+
+ /**
+ * Parse the color string, and return the corresponding color-int.
+ * If the string cannot be parsed, throws an IllegalArgumentException
+ * exception. Supported formats are:
+ * #RRGGBB
+ * #AARRGGBB
+ * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta',
+ * 'yellow', 'lightgray', 'darkgray'
+ */
+ public static int parseColor(String colorString) {
+ if (colorString.charAt(0) == '#') {
+ // Use a long to avoid rollovers on #ffXXXXXX
+ long color = Long.parseLong(colorString.substring(1), 16);
+ if (colorString.length() == 7) {
+ // Set the alpha value
+ color |= 0x00000000ff000000;
+ } else if (colorString.length() != 9) {
+ throw new IllegalArgumentException("Unknown color");
+ }
+ return (int)color;
+ } else {
+ Integer color = sColorNameMap.get(colorString.toLowerCase(Locale.US));
+ if (color != null) {
+ return color;
+ }
+ }
+ throw new IllegalArgumentException("Unknown color");
+ }
+
+ /**
+ * Convert RGB components to HSV.
+ * hsv[0] is Hue [0 .. 360)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * @param red red component value [0..255]
+ * @param green green component value [0..255]
+ * @param blue blue component value [0..255]
+ * @param hsv 3 element array which holds the resulting HSV components.
+ */
+ public static void RGBToHSV(int red, int green, int blue, float hsv[]) {
+ if (hsv.length < 3) {
+ throw new RuntimeException("3 components required for hsv");
+ }
+ nativeRGBToHSV(red, green, blue, hsv);
+ }
+
+ /**
+ * Convert the argb color to its HSV components.
+ * hsv[0] is Hue [0 .. 360)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * @param color the argb color to convert. The alpha component is ignored.
+ * @param hsv 3 element array which holds the resulting HSV components.
+ */
+ public static void colorToHSV(int color, float hsv[]) {
+ RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv);
+ }
+
+ /**
+ * Convert HSV components to an ARGB color. Alpha set to 0xFF.
+ * hsv[0] is Hue [0 .. 360)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * If hsv values are out of range, they are pinned.
+ * @param hsv 3 element array which holds the input HSV components.
+ * @return the resulting argb color
+ */
+ public static int HSVToColor(float hsv[]) {
+ return HSVToColor(0xFF, hsv);
+ }
+
+ /**
+ * Convert HSV components to an ARGB color. The alpha component is passed
+ * through unchanged.
+ * hsv[0] is Hue [0 .. 360)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * If hsv values are out of range, they are pinned.
+ * @param alpha the alpha component of the returned argb color.
+ * @param hsv 3 element array which holds the input HSV components.
+ * @return the resulting argb color
+ */
+ public static int HSVToColor(int alpha, float hsv[]) {
+ if (hsv.length < 3) {
+ throw new RuntimeException("3 components required for hsv");
+ }
+ return nativeHSVToColor(alpha, hsv);
+ }
+
+ private static native void nativeRGBToHSV(int red, int greed, int blue,
+ float hsv[]);
+ private static native int nativeHSVToColor(int alpha, float hsv[]);
+
+ private static final HashMap<String, Integer> sColorNameMap;
+
+ static {
+ sColorNameMap = new HashMap();
+ sColorNameMap.put("black", Integer.valueOf(BLACK));
+ sColorNameMap.put("darkgray", Integer.valueOf(DKGRAY));
+ sColorNameMap.put("gray", Integer.valueOf(GRAY));
+ sColorNameMap.put("lightgray", Integer.valueOf(LTGRAY));
+ sColorNameMap.put("white", Integer.valueOf(WHITE));
+ sColorNameMap.put("red", Integer.valueOf(RED));
+ sColorNameMap.put("green", Integer.valueOf(GREEN));
+ sColorNameMap.put("blue", Integer.valueOf(BLUE));
+ sColorNameMap.put("yellow", Integer.valueOf(YELLOW));
+ sColorNameMap.put("cyan", Integer.valueOf(CYAN));
+ sColorNameMap.put("magenta", Integer.valueOf(MAGENTA));
+ }
+}
+
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
new file mode 100644
index 0000000..76f2c7f
--- /dev/null
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+// This file was generated from the C++ include file: SkColorFilter.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+package android.graphics;
+
+
+public class ColorFilter {
+
+ protected void finalize() throws Throwable {
+ finalizer(native_instance);
+ }
+
+ private static native void finalizer(int native_instance);
+
+ int native_instance;
+}
diff --git a/graphics/java/android/graphics/ColorMatrix.java b/graphics/java/android/graphics/ColorMatrix.java
new file mode 100644
index 0000000..2478712
--- /dev/null
+++ b/graphics/java/android/graphics/ColorMatrix.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2007 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 android.util.FloatMath;
+
+/**
+ * 5x4 matrix for transforming the color+alpha components of a Bitmap.
+ * The matrix is stored in a single array, and its treated as follows:
+ * [ a, b, c, d, e,
+ * f, g, h, i, j,
+ * k, l, m, n, o,
+ * p, q, r, s, t ]
+ *
+ * When applied to a color [r, g, b, a], the resulting color is computed as
+ * (after clamping)
+ * R' = a*R + b*G + c*B + d*A + e;
+ * G' = f*R + g*G + h*B + i*A + j;
+ * B' = k*R + l*G + m*B + n*A + o;
+ * A' = p*R + q*G + r*B + s*A + t;
+ */
+public class ColorMatrix {
+
+ private final float[] mArray = new float[20];
+
+ /**
+ * Create a new colormatrix initialized to identity (as if reset() had
+ * been called).
+ */
+ public ColorMatrix() {
+ reset();
+ }
+
+ /**
+ * Create a new colormatrix initialized with the specified array of values.
+ */
+ public ColorMatrix(float[] src) {
+ System.arraycopy(src, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Create a new colormatrix initialized with the specified colormatrix.
+ */
+ public ColorMatrix(ColorMatrix src) {
+ System.arraycopy(src.mArray, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Return the array of floats representing this colormatrix.
+ */
+ public final float[] getArray() { return mArray; }
+
+ /**
+ * Set this colormatrix to identity:
+ * [ 1 0 0 0 0 - red vector
+ * 0 1 0 0 0 - green vector
+ * 0 0 1 0 0 - blue vector
+ * 0 0 0 1 0 ] - alpha vector
+ */
+ public void reset() {
+ final float[] a = mArray;
+
+ for (int i = 19; i > 0; --i) {
+ a[i] = 0;
+ }
+ a[0] = a[6] = a[12] = a[18] = 1;
+ }
+
+ /**
+ * Assign the src colormatrix into this matrix, copying all of its values.
+ */
+ public void set(ColorMatrix src) {
+ System.arraycopy(src.mArray, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Assign the array of floats into this matrix, copying all of its values.
+ */
+ public void set(float[] src) {
+ System.arraycopy(src, 0, mArray, 0, 20);
+ }
+
+ /**
+ * Set this colormatrix to scale by the specified values.
+ */
+ public void setScale(float rScale, float gScale, float bScale,
+ float aScale) {
+ final float[] a = mArray;
+
+ for (int i = 19; i > 0; --i) {
+ a[i] = 0;
+ }
+ a[0] = rScale;
+ a[6] = gScale;
+ a[12] = bScale;
+ a[18] = aScale;
+ }
+
+ public void setRotate(int axis, float degrees) {
+ reset();
+ float radians = degrees * (float)Math.PI / 180;
+ float cosine = FloatMath.cos(radians);
+ float sine = FloatMath.sin(radians);
+ switch (axis) {
+ case 0:
+ mArray[6] = mArray[12] = cosine;
+ mArray[7] = sine;
+ mArray[11] = -sine;
+ break;
+ case 1:
+ mArray[0] = mArray[17] = cosine;
+ mArray[2] = sine;
+ mArray[15] = -sine;
+ break;
+ case 2:
+ mArray[0] = mArray[6] = cosine;
+ mArray[1] = sine;
+ mArray[5] = -sine;
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Set this colormatrix to the concatenation of the two specified
+ * colormatrices, such that the resulting colormatrix has the same effect
+ * as applying matB and then applying matA. It is legal for either matA or
+ * matB to be the same colormatrix as this.
+ */
+ public void setConcat(ColorMatrix matA, ColorMatrix matB) {
+ float[] tmp = null;
+
+ if (matA == this || matB == this) {
+ tmp = new float[20];
+ }
+ else {
+ tmp = mArray;
+ }
+
+ final float[] a = matA.mArray;
+ final float[] b = matB.mArray;
+ int index = 0;
+ for (int j = 0; j < 20; j += 5) {
+ for (int i = 0; i < 4; i++) {
+ tmp[index++] = a[j + 0] * b[i + 0] + a[j + 1] * b[i + 5] +
+ a[j + 2] * b[i + 10] + a[j + 3] * b[i + 15];
+ }
+ tmp[index++] = a[j + 0] * b[4] + a[j + 1] * b[9] +
+ a[j + 2] * b[14] + a[j + 3] * b[19] +
+ a[j + 4];
+ }
+
+ if (tmp != mArray) {
+ System.arraycopy(tmp, 0, mArray, 0, 20);
+ }
+ }
+
+ /**
+ * Concat this colormatrix with the specified prematrix. This is logically
+ * the same as calling setConcat(this, prematrix);
+ */
+ public void preConcat(ColorMatrix prematrix) {
+ setConcat(this, prematrix);
+ }
+
+ /**
+ * Concat this colormatrix with the specified postmatrix. This is logically
+ * the same as calling setConcat(postmatrix, this);
+ */
+ public void postConcat(ColorMatrix postmatrix) {
+ setConcat(postmatrix, this);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set the matrix to affect the saturation of colors. A value of 0 maps the
+ * color to gray-scale. 1 is identity.
+ */
+ public void setSaturation(float sat) {
+ reset();
+ float[] m = mArray;
+
+ final float invSat = 1 - sat;
+ final float R = 0.213f * invSat;
+ final float G = 0.715f * invSat;
+ final float B = 0.072f * invSat;
+
+ m[0] = R + sat; m[1] = G; m[2] = B;
+ m[5] = R; m[6] = G + sat; m[7] = B;
+ m[10] = R; m[11] = G; m[12] = B + sat;
+ }
+
+ /**
+ * Set the matrix to convert RGB to YUV
+ */
+ public void setRGB2YUV() {
+ reset();
+ float[] m = mArray;
+ // these coefficients match those in libjpeg
+ m[0] = 0.299f; m[1] = 0.587f; m[2] = 0.114f;
+ m[5] = -0.16874f; m[6] = -0.33126f; m[7] = 0.5f;
+ m[10] = 0.5f; m[11] = -0.41869f; m[12] = -0.08131f;
+ }
+
+ /**
+ * Set the matrix to convert from YUV to RGB
+ */
+ public void setYUV2RGB() {
+ reset();
+ float[] m = mArray;
+ // these coefficients match those in libjpeg
+ m[2] = 1.402f;
+ m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f;
+ m[10] = 1; m[11] = 1.772f; m[12] = 0;
+ }
+}
+
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
new file mode 100644
index 0000000..5d73cff
--- /dev/null
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class ColorMatrixColorFilter extends ColorFilter {
+ /**
+ * Create a colorfilter that transforms colors through a 4x5 color matrix.
+ *
+ * @param matrix 4x5 matrix used to transform colors. It is copied into
+ * the filter, so changes made to the matrix after the filter
+ * is constructed will not be reflected in the filter.
+ */
+ public ColorMatrixColorFilter(ColorMatrix matrix) {
+ native_instance = nativeColorMatrixFilter(matrix.getArray());
+ }
+
+ /**
+ * Create a colorfilter that transforms colors through a 4x5 color matrix.
+ *
+ * @param array array of floats used to transform colors, treated as a 4x5
+ * matrix. The first 20 entries of the array are copied into
+ * the filter. See ColorMatrix.
+ */
+ public ColorMatrixColorFilter(float[] array) {
+ if (array.length < 20) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_instance = nativeColorMatrixFilter(array);
+ }
+
+ private static native int nativeColorMatrixFilter(float[] array);
+}
diff --git a/graphics/java/android/graphics/ComposePathEffect.java b/graphics/java/android/graphics/ComposePathEffect.java
new file mode 100644
index 0000000..beac78e
--- /dev/null
+++ b/graphics/java/android/graphics/ComposePathEffect.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class ComposePathEffect extends PathEffect {
+
+ /**
+ * Construct a PathEffect whose effect is to apply first the inner effect
+ * and the the outer pathEffect (e.g. outer(inner(path))).
+ */
+ public ComposePathEffect(PathEffect outerpe, PathEffect innerpe) {
+ native_instance = nativeCreate(outerpe.native_instance,
+ innerpe.native_instance);
+ }
+
+ private static native int nativeCreate(int outerpe, int innerpe);
+}
+
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
new file mode 100644
index 0000000..a06d30b
--- /dev/null
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 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;
+
+/** A subclass of shader that returns the coposition of two other shaders, combined by
+ an {@link android.graphics.Xfermode} subclass.
+*/
+public class ComposeShader extends Shader {
+ /** Create a new compose shader, given shaders A, B, and a combining mode.
+ When the mode is applied, it will be given the result from shader A as its
+ "dst", and the result of from shader B as its "src".
+ @param shaderA The colors from this shader are seen as the "dst" by the mode
+ @param shaderB The colors from this shader are seen as the "src" by the mode
+ @param mode The mode that combines the colors from the two shaders. If mode
+ is null, then SRC_OVER is assumed.
+ */
+ public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
+ native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
+ (mode != null) ? mode.native_instance : 0);
+ }
+
+ /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
+ When the mode is applied, it will be given the result from shader A as its
+ "dst", and the result of from shader B as its "src".
+ @param shaderA The colors from this shader are seen as the "dst" by the mode
+ @param shaderB The colors from this shader are seen as the "src" by the mode
+ @param mode The PorterDuff mode that combines the colors from the two shaders.
+ */
+ public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
+ native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
+ mode.nativeInt);
+ }
+
+ private static native int nativeCreate1(int native_shaderA, int native_shaderB, int native_mode);
+ private static native int nativeCreate2(int native_shaderA, int native_shaderB, int porterDuffMode);
+}
+
diff --git a/graphics/java/android/graphics/CornerPathEffect.java b/graphics/java/android/graphics/CornerPathEffect.java
new file mode 100644
index 0000000..400c886
--- /dev/null
+++ b/graphics/java/android/graphics/CornerPathEffect.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class CornerPathEffect extends PathEffect {
+
+ /**
+ * Transforms geometries that are drawn (either STROKE or FILL styles) by
+ * replacing any sharp angles between line segments into rounded angles of
+ * the specified radius.
+ * @param radius Amount to round sharp angles between line segments.
+ */
+ public CornerPathEffect(float radius) {
+ native_instance = nativeCreate(radius);
+ }
+
+ private static native int nativeCreate(float radius);
+}
+
diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java
new file mode 100644
index 0000000..3deca4a
--- /dev/null
+++ b/graphics/java/android/graphics/DashPathEffect.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class DashPathEffect extends PathEffect {
+
+ /**
+ * The intervals array must contain an even number of entries (>=2), with
+ * the even indices specifying the "on" intervals, and the odd indices
+ * specifying the "off" intervals. phase is an offset into the intervals
+ * array (mod the sum of all of the intervals). The intervals array
+ * controlls the width of the dashes. The paint's strokeWidth controlls the
+ * height of the dashes.
+ * Note: this patheffect only affects drawing with the paint's style is set
+ * to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
+ * style == FILL.
+ * @param intervals array of ON and OFF distances
+ * @param phase offset before the first ON interval is drawn
+ */
+ public DashPathEffect(float intervals[], float phase) {
+ if (intervals.length < 2) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_instance = nativeCreate(intervals, phase);
+ }
+
+ private static native int nativeCreate(float intervals[], float phase);
+}
+
diff --git a/graphics/java/android/graphics/DiscretePathEffect.java b/graphics/java/android/graphics/DiscretePathEffect.java
new file mode 100644
index 0000000..de8b2f0
--- /dev/null
+++ b/graphics/java/android/graphics/DiscretePathEffect.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+public class DiscretePathEffect extends PathEffect {
+
+ /**
+ * Chop the path into lines of segmentLength, randomly deviating from the
+ * original path by deviation.
+ */
+ public DiscretePathEffect(float segmentLength, float deviation) {
+ native_instance = nativeCreate(segmentLength, deviation);
+ }
+
+ private static native int nativeCreate(float length, float deviation);
+}
+
diff --git a/graphics/java/android/graphics/DrawFilter.java b/graphics/java/android/graphics/DrawFilter.java
new file mode 100644
index 0000000..6b44ed7
--- /dev/null
+++ b/graphics/java/android/graphics/DrawFilter.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * A DrawFilter subclass can be installed in a Canvas. When it is present, it
+ * can modify the paint that is used to draw (temporarily). With this, a filter
+ * can disable/enable antialiasing, or change the color for everything this is
+ * drawn.
+ */
+public class DrawFilter {
+
+ // this is set by subclasses, but don't make it public
+ /* package */ int mNativeInt; // pointer to native object
+
+ protected void finalize() throws Throwable {
+ nativeDestructor(mNativeInt);
+ }
+
+ private static native void nativeDestructor(int nativeDrawFilter);
+}
+
diff --git a/graphics/java/android/graphics/EmbossMaskFilter.java b/graphics/java/android/graphics/EmbossMaskFilter.java
new file mode 100644
index 0000000..5dd8611
--- /dev/null
+++ b/graphics/java/android/graphics/EmbossMaskFilter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class EmbossMaskFilter extends MaskFilter {
+ /**
+ * Create an emboss maskfilter
+ *
+ * @param direction array of 3 scalars [x, y, z] specifying the direction of the light source
+ * @param ambient 0...1 amount of ambient light
+ * @param specular coefficient for specular highlights (e.g. 8)
+ * @param blurRadius amount to blur before applying lighting (e.g. 3)
+ * @return the emboss maskfilter
+ */
+ public EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius) {
+ if (direction.length < 3) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_instance = nativeConstructor(direction, ambient, specular, blurRadius);
+ }
+
+ private static native int nativeConstructor(float[] direction, float ambient, float specular, float blurRadius);
+}
+
diff --git a/graphics/java/android/graphics/Interpolator.java b/graphics/java/android/graphics/Interpolator.java
new file mode 100644
index 0000000..75851a6
--- /dev/null
+++ b/graphics/java/android/graphics/Interpolator.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 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 android.os.SystemClock;
+
+public class Interpolator {
+
+ public Interpolator(int valueCount) {
+ mValueCount = valueCount;
+ mFrameCount = 2;
+ native_instance = nativeConstructor(valueCount, 2);
+ }
+
+ public Interpolator(int valueCount, int frameCount) {
+ mValueCount = valueCount;
+ mFrameCount = frameCount;
+ native_instance = nativeConstructor(valueCount, frameCount);
+ }
+
+ /**
+ * Reset the Interpolator to have the specified number of values and an
+ * implicit keyFrame count of 2 (just a start and end). After this call the
+ * values for each keyFrame must be assigned using setKeyFrame().
+ */
+ public void reset(int valueCount) {
+ reset(valueCount, 2);
+ }
+
+ /**
+ * Reset the Interpolator to have the specified number of values and
+ * keyFrames. After this call the values for each keyFrame must be assigned
+ * using setKeyFrame().
+ */
+ public void reset(int valueCount, int frameCount) {
+ mValueCount = valueCount;
+ mFrameCount = frameCount;
+ nativeReset(native_instance, valueCount, frameCount);
+ }
+
+ public final int getKeyFrameCount() {
+ return mFrameCount;
+ }
+
+ public final int getValueCount() {
+ return mValueCount;
+ }
+
+ /**
+ * Assign the keyFrame (specified by index) a time value and an array of key
+ * values (with an implicity blend array of [0, 0, 1, 1] giving linear
+ * transition to the next set of key values).
+ *
+ * @param index The index of the key frame to assign
+ * @param msec The time (in mililiseconds) for this key frame. Based on the
+ * SystemClock.uptimeMillis() clock
+ * @param values Array of values associated with theis key frame
+ */
+ public void setKeyFrame(int index, int msec, float[] values) {
+ setKeyFrame(index, msec, values, null);
+ }
+
+ /**
+ * Assign the keyFrame (specified by index) a time value and an array of key
+ * values and blend array.
+ *
+ * @param index The index of the key frame to assign
+ * @param msec The time (in mililiseconds) for this key frame. Based on the
+ * SystemClock.uptimeMillis() clock
+ * @param values Array of values associated with theis key frame
+ * @param blend (may be null) Optional array of 4 blend values
+ */
+ public void setKeyFrame(int index, int msec, float[] values, float[] blend) {
+ if (index < 0 || index >= mFrameCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (values.length < mValueCount) {
+ throw new ArrayStoreException();
+ }
+ if (blend != null && blend.length < 4) {
+ throw new ArrayStoreException();
+ }
+ nativeSetKeyFrame(native_instance, index, msec, values, blend);
+ }
+
+ /**
+ * Set a repeat count (which may be fractional) for the interpolator, and
+ * whether the interpolator should mirror its repeats. The default settings
+ * are repeatCount = 1, and mirror = false.
+ */
+ public void setRepeatMirror(float repeatCount, boolean mirror) {
+ if (repeatCount >= 0) {
+ nativeSetRepeatMirror(native_instance, repeatCount, mirror);
+ }
+ }
+
+ public enum Result {
+ NORMAL,
+ FREEZE_START,
+ FREEZE_END
+ }
+
+ /**
+ * Calls timeToValues(msec, values) with the msec set to now (by calling
+ * (int)SystemClock.uptimeMillis().)
+ */
+ public Result timeToValues(float[] values) {
+ return timeToValues((int)SystemClock.uptimeMillis(), values);
+ }
+
+ /**
+ * Given a millisecond time value (msec), return the interpolated values and
+ * return whether the specified time was within the range of key times
+ * (NORMAL), was before the first key time (FREEZE_START) or after the last
+ * key time (FREEZE_END). In any event, computed values are always returned.
+ *
+ * @param msec The time (in milliseconds) used to sample into the
+ * Interpolator. Based on the SystemClock.uptimeMillis() clock
+ * @param values Where to write the computed values (may be NULL).
+ * @return how the values were computed (even if values == null)
+ */
+ public Result timeToValues(int msec, float[] values) {
+ if (values != null && values.length < mValueCount) {
+ throw new ArrayStoreException();
+ }
+ switch (nativeTimeToValues(native_instance, msec, values)) {
+ case 0: return Result.NORMAL;
+ case 1: return Result.FREEZE_START;
+ default: return Result.FREEZE_END;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ nativeDestructor(native_instance);
+ }
+
+ private int mValueCount;
+ private int mFrameCount;
+ private final int native_instance;
+
+ private static native int nativeConstructor(int valueCount, int frameCount);
+ private static native void nativeDestructor(int native_instance);
+ private static native void nativeReset(int native_instance, int valueCount, int frameCount);
+ private static native void nativeSetKeyFrame(int native_instance, int index, int msec, float[] values, float[] blend);
+ private static native void nativeSetRepeatMirror(int native_instance, float repeatCount, boolean mirror);
+ private static native int nativeTimeToValues(int native_instance, int msec, float[] values);
+}
+
diff --git a/graphics/java/android/graphics/LayerRasterizer.java b/graphics/java/android/graphics/LayerRasterizer.java
new file mode 100644
index 0000000..9bd55a5
--- /dev/null
+++ b/graphics/java/android/graphics/LayerRasterizer.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class LayerRasterizer extends Rasterizer {
+ public LayerRasterizer() {
+ native_instance = nativeConstructor();
+ }
+
+ /** Add a new layer (above any previous layers) to the rasterizer.
+ The layer will extract those fields that affect the mask from
+ the specified paint, but will not retain a reference to the paint
+ object itself, so it may be reused without danger of side-effects.
+ */
+ public void addLayer(Paint paint, float dx, float dy) {
+ nativeAddLayer(native_instance, paint.mNativePaint, dx, dy);
+ }
+
+ public void addLayer(Paint paint) {
+ nativeAddLayer(native_instance, paint.mNativePaint, 0, 0);
+ }
+
+ private static native int nativeConstructor();
+ private static native void nativeAddLayer(int native_layer, int native_paint, float dx, float dy);
+}
+
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
new file mode 100644
index 0000000..5562389
--- /dev/null
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+// This file was generated from the C++ include file: SkColorFilter.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+package android.graphics;
+
+public class LightingColorFilter extends ColorFilter {
+
+ /**
+ * Create a colorfilter that multiplies the RGB channels by one color, and then adds a second color,
+ * pinning the result for each component to [0..255]. The alpha components of the mul and add arguments
+ * are ignored.
+ */
+ public LightingColorFilter(int mul, int add) {
+ native_instance = native_CreateLightingFilter(mul, add);
+ }
+
+ private static native int native_CreateLightingFilter(int mul, int add);
+}
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
new file mode 100644
index 0000000..e3db105
--- /dev/null
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class LinearGradient extends Shader {
+
+ /** Create a shader that draws a linear gradient along a line.
+ @param x0 The x-coordinate for the start of the gradient line
+ @param y0 The y-coordinate for the start of the gradient line
+ @param x1 The x-coordinate for the end of the gradient line
+ @param y1 The y-coordinate for the end of the gradient line
+ @param colors The colors to be distributed along the gradient line
+ @param positions May be null. The relative positions [0..1] of
+ each corresponding color in the colors array. If this is null,
+ the the colors are distributed evenly along the gradient line.
+ @param tile The Shader tiling mode
+ */
+ public LinearGradient(float x0, float y0, float x1, float y1,
+ int colors[], float positions[], TileMode tile) {
+ if (colors.length < 2) {
+ throw new IllegalArgumentException("needs >= 2 number of colors");
+ }
+ if (positions != null && colors.length != positions.length) {
+ throw new IllegalArgumentException("color and position arrays must be of equal length");
+ }
+ native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
+ }
+
+ /** Create a shader that draws a linear gradient along a line.
+ @param x0 The x-coordinate for the start of the gradient line
+ @param y0 The y-coordinate for the start of the gradient line
+ @param x1 The x-coordinate for the end of the gradient line
+ @param y1 The y-coordinate for the end of the gradient line
+ @param color0 The color at the start of the gradient line.
+ @param color1 The color at the end of the gradient line.
+ @param tile The Shader tiling mode
+ */
+ public LinearGradient(float x0, float y0, float x1, float y1,
+ int color0, int color1, TileMode tile) {
+ native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
+ }
+
+
+ private static native int nativeCreate1(float x0, float y0, float x1, float y1,
+ int colors[], float positions[], int tileMode);
+ private static native int nativeCreate2(float x0, float y0, float x1, float y1,
+ int color0, int color1, int tileMode);
+}
+
diff --git a/graphics/java/android/graphics/MaskFilter.java b/graphics/java/android/graphics/MaskFilter.java
new file mode 100644
index 0000000..4ebb619
--- /dev/null
+++ b/graphics/java/android/graphics/MaskFilter.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 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;
+
+/**
+ * MaskFilter is the base class for object that perform transformations on
+ * an alpha-channel mask before drawing it. A subclass of MaskFilter may be
+ * installed into a Paint. Blur and emboss are implemented as subclasses of MaskFilter.
+ */
+public class MaskFilter {
+
+ protected void finalize() throws Throwable {
+ nativeDestructor(native_instance);
+ }
+
+ private static native void nativeDestructor(int native_filter);
+ int native_instance;
+}
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
new file mode 100644
index 0000000..2681eae
--- /dev/null
+++ b/graphics/java/android/graphics/Matrix.java
@@ -0,0 +1,639 @@
+/*
+ * Copyright (C) 2006 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;
+
+
+/**
+ * The Matrix class holds a 3x3 matrix for transforming coordinates.
+ * Matrix does not have a constructor, so it must be explicitly initialized
+ * using either reset() - to construct an identity matrix, or one of the set..()
+ * functions (e.g. setTranslate, setRotate, etc.).
+ */
+public class Matrix {
+
+ public static final int MSCALE_X = 0; //!< use with getValues/setValues
+ public static final int MSKEW_X = 1; //!< use with getValues/setValues
+ public static final int MTRANS_X = 2; //!< use with getValues/setValues
+ public static final int MSKEW_Y = 3; //!< use with getValues/setValues
+ public static final int MSCALE_Y = 4; //!< use with getValues/setValues
+ public static final int MTRANS_Y = 5; //!< use with getValues/setValues
+ public static final int MPERSP_0 = 6; //!< use with getValues/setValues
+ public static final int MPERSP_1 = 7; //!< use with getValues/setValues
+ public static final int MPERSP_2 = 8; //!< use with getValues/setValues
+
+ /* package */ int native_instance;
+
+ /**
+ * Create an identity matrix
+ */
+ public Matrix() {
+ native_instance = native_create(0);
+ }
+
+ /**
+ * Create a matrix that is a (deep) copy of src
+ * @param src The matrix to copy into this matrix
+ */
+ public Matrix(Matrix src) {
+ native_instance = native_create(src != null ? src.native_instance : 0);
+ }
+
+ /**
+ * Returns true if the matrix is identity.
+ * This maybe faster than testing if (getType() == 0)
+ */
+ public boolean isIdentity() {
+ return native_isIdentity(native_instance);
+ }
+
+ /**
+ * Returns true if will map a rectangle to another rectangle. This can be
+ * true if the matrix is identity, scale-only, or rotates a multiple of 90
+ * degrees.
+ */
+ public boolean rectStaysRect() {
+ return native_rectStaysRect(native_instance);
+ }
+
+ /**
+ * (deep) copy the src matrix into this matrix. If src is null, reset this
+ * matrix to the identity matrix.
+ */
+ public void set(Matrix src) {
+ if (src == null) {
+ reset();
+ } else {
+ native_set(native_instance, src.native_instance);
+ }
+ }
+
+ /** Returns true iff obj is a Matrix and its values equal our values.
+ */
+ public boolean equals(Object obj) {
+ return obj != null &&
+ obj instanceof Matrix &&
+ native_equals(native_instance, ((Matrix)obj).native_instance);
+ }
+
+ /** Set the matrix to identity */
+ public void reset() {
+ native_reset(native_instance);
+ }
+
+ /** Set the matrix to translate by (dx, dy). */
+ public void setTranslate(float dx, float dy) {
+ native_setTranslate(native_instance, dx, dy);
+ }
+
+ /**
+ * Set the matrix to scale by sx and sy, with a pivot point at (px, py).
+ * The pivot point is the coordinate that should remain unchanged by the
+ * specified transformation.
+ */
+ public void setScale(float sx, float sy, float px, float py) {
+ native_setScale(native_instance, sx, sy, px, py);
+ }
+
+ /** Set the matrix to scale by sx and sy. */
+ public void setScale(float sx, float sy) {
+ native_setScale(native_instance, sx, sy);
+ }
+
+ /**
+ * Set the matrix to rotate by the specified number of degrees, with a pivot
+ * point at (px, py). The pivot point is the coordinate that should remain
+ * unchanged by the specified transformation.
+ */
+ public void setRotate(float degrees, float px, float py) {
+ native_setRotate(native_instance, degrees, px, py);
+ }
+
+ /**
+ * Set the matrix to rotate about (0,0) by the specified number of degrees.
+ */
+ public void setRotate(float degrees) {
+ native_setRotate(native_instance, degrees);
+ }
+
+ /**
+ * Set the matrix to rotate by the specified sine and cosine values, with a
+ * pivot point at (px, py). The pivot point is the coordinate that should
+ * remain unchanged by the specified transformation.
+ */
+ public void setSinCos(float sinValue, float cosValue, float px, float py) {
+ native_setSinCos(native_instance, sinValue, cosValue, px, py);
+ }
+
+ /** Set the matrix to rotate by the specified sine and cosine values. */
+ public void setSinCos(float sinValue, float cosValue) {
+ native_setSinCos(native_instance, sinValue, cosValue);
+ }
+
+ /**
+ * Set the matrix to skew by sx and sy, with a pivot point at (px, py).
+ * The pivot point is the coordinate that should remain unchanged by the
+ * specified transformation.
+ */
+ public void setSkew(float kx, float ky, float px, float py) {
+ native_setSkew(native_instance, kx, ky, px, py);
+ }
+
+ /** Set the matrix to skew by sx and sy. */
+ public void setSkew(float kx, float ky) {
+ native_setSkew(native_instance, kx, ky);
+ }
+
+ /**
+ * Set the matrix to the concatenation of the two specified matrices,
+ * returning true if the the result can be represented. Either of the two
+ * matrices may also be the target matrix. this = a * b
+ */
+ public boolean setConcat(Matrix a, Matrix b) {
+ return native_setConcat(native_instance, a.native_instance,
+ b.native_instance);
+ }
+
+ /**
+ * Preconcats the matrix with the specified translation.
+ * M' = M * T(dx, dy)
+ */
+ public boolean preTranslate(float dx, float dy) {
+ return native_preTranslate(native_instance, dx, dy);
+ }
+
+ /**
+ * Preconcats the matrix with the specified scale.
+ * M' = M * S(sx, sy, px, py)
+ */
+ public boolean preScale(float sx, float sy, float px, float py) {
+ return native_preScale(native_instance, sx, sy, px, py);
+ }
+
+ /**
+ * Preconcats the matrix with the specified scale.
+ * M' = M * S(sx, sy)
+ */
+ public boolean preScale(float sx, float sy) {
+ return native_preScale(native_instance, sx, sy);
+ }
+
+ /**
+ * Preconcats the matrix with the specified rotation.
+ * M' = M * R(degrees, px, py)
+ */
+ public boolean preRotate(float degrees, float px, float py) {
+ return native_preRotate(native_instance, degrees, px, py);
+ }
+
+ /**
+ * Preconcats the matrix with the specified rotation.
+ * M' = M * R(degrees)
+ */
+ public boolean preRotate(float degrees) {
+ return native_preRotate(native_instance, degrees);
+ }
+
+ /**
+ * Preconcats the matrix with the specified skew.
+ * M' = M * K(kx, ky, px, py)
+ */
+ public boolean preSkew(float kx, float ky, float px, float py) {
+ return native_preSkew(native_instance, kx, ky, px, py);
+ }
+
+ /**
+ * Preconcats the matrix with the specified skew.
+ * M' = M * K(kx, ky)
+ */
+ public boolean preSkew(float kx, float ky) {
+ return native_preSkew(native_instance, kx, ky);
+ }
+
+ /**
+ * Preconcats the matrix with the specified matrix.
+ * M' = M * other
+ */
+ public boolean preConcat(Matrix other) {
+ return native_preConcat(native_instance, other.native_instance);
+ }
+
+ /**
+ * Postconcats the matrix with the specified translation.
+ * M' = T(dx, dy) * M
+ */
+ public boolean postTranslate(float dx, float dy) {
+ return native_postTranslate(native_instance, dx, dy);
+ }
+
+ /**
+ * Postconcats the matrix with the specified scale.
+ * M' = S(sx, sy, px, py) * M
+ */
+ public boolean postScale(float sx, float sy, float px, float py) {
+ return native_postScale(native_instance, sx, sy, px, py);
+ }
+
+ /**
+ * Postconcats the matrix with the specified scale.
+ * M' = S(sx, sy) * M
+ */
+ public boolean postScale(float sx, float sy) {
+ return native_postScale(native_instance, sx, sy);
+ }
+
+ /**
+ * Postconcats the matrix with the specified rotation.
+ * M' = R(degrees, px, py) * M
+ */
+ public boolean postRotate(float degrees, float px, float py) {
+ return native_postRotate(native_instance, degrees, px, py);
+ }
+
+ /**
+ * Postconcats the matrix with the specified rotation.
+ * M' = R(degrees) * M
+ */
+ public boolean postRotate(float degrees) {
+ return native_postRotate(native_instance, degrees);
+ }
+
+ /**
+ * Postconcats the matrix with the specified skew.
+ * M' = K(kx, ky, px, py) * M
+ */
+ public boolean postSkew(float kx, float ky, float px, float py) {
+ return native_postSkew(native_instance, kx, ky, px, py);
+ }
+
+ /**
+ * Postconcats the matrix with the specified skew.
+ * M' = K(kx, ky) * M
+ */
+ public boolean postSkew(float kx, float ky) {
+ return native_postSkew(native_instance, kx, ky);
+ }
+
+ /**
+ * Postconcats the matrix with the specified matrix.
+ * M' = other * M
+ */
+ public boolean postConcat(Matrix other) {
+ return native_postConcat(native_instance, other.native_instance);
+ }
+
+ /** Controlls how the src rect should align into the dst rect for
+ setRectToRect().
+ */
+ public enum ScaleToFit {
+ /**
+ * Scale in X and Y independently, so that src matches dst exactly.
+ * This may change the aspect ratio of the src.
+ */
+ FILL (0),
+ /**
+ * Compute a scale that will maintain the original src aspect ratio,
+ * but will also ensure that src fits entirely inside dst. At least one
+ * axis (X or Y) will fit exactly. START aligns the result to the
+ * left and top edges of dst.
+ */
+ START (1),
+ /**
+ * Compute a scale that will maintain the original src aspect ratio,
+ * but will also ensure that src fits entirely inside dst. At least one
+ * axis (X or Y) will fit exactly. The result is centered inside dst.
+ */
+ CENTER (2),
+ /**
+ * Compute a scale that will maintain the original src aspect ratio,
+ * but will also ensure that src fits entirely inside dst. At least one
+ * axis (X or Y) will fit exactly. END aligns the result to the
+ * right and bottom edges of dst.
+ */
+ END (3);
+
+ // the native values must match those in SkMatrix.h
+ ScaleToFit(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Set the matrix to the scale and translate values that map the source
+ * rectangle to the destination rectangle, returning true if the the result
+ * can be represented.
+ *
+ * @param src the source rectangle to map from.
+ * @param dst the destination rectangle to map to.
+ * @param stf the ScaleToFit option
+ * @return true if the matrix can be represented by the rectangle mapping.
+ */
+ public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
+ if (dst == null || src == null) {
+ throw new NullPointerException();
+ }
+ return native_setRectToRect(native_instance, src, dst, stf.nativeInt);
+ }
+
+ // private helper to perform range checks on arrays of "points"
+ private static void checkPointArrays(float[] src, int srcIndex,
+ float[] dst, int dstIndex,
+ int pointCount) {
+ // check for too-small and too-big indices
+ int srcStop = srcIndex + (pointCount << 1);
+ int dstStop = dstIndex + (pointCount << 1);
+ if ((pointCount | srcIndex | dstIndex | srcStop | dstStop) < 0 ||
+ srcStop > src.length || dstStop > dst.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set the matrix such that the specified src points would map to the
+ * specified dst points. The "points" are represented as an array of floats,
+ * order [x0, y0, x1, y1, ...], where each "point" is 2 float values.
+ *
+ * @param src The array of src [x,y] pairs (points)
+ * @param srcIndex Index of the first pair of src values
+ * @param dst The array of dst [x,y] pairs (points)
+ * @param dstIndex Index of the first pair of dst values
+ * @param pointCount The number of pairs/points to be used. Must be [0..4]
+ * @return true if the matrix was set to the specified transformation
+ */
+ public boolean setPolyToPoly(float[] src, int srcIndex,
+ float[] dst, int dstIndex,
+ int pointCount) {
+ if (pointCount > 4) {
+ throw new IllegalArgumentException();
+ }
+ checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
+ return native_setPolyToPoly(native_instance, src, srcIndex,
+ dst, dstIndex, pointCount);
+ }
+
+ /**
+ * If this matrix can be inverted, return true and if inverse is not null,
+ * set inverse to be the inverse of this matrix. If this matrix cannot be
+ * inverted, ignore inverse and return false.
+ */
+ public boolean invert(Matrix inverse) {
+ return native_invert(native_instance, inverse.native_instance);
+ }
+
+ /**
+ * Apply this matrix to the array of 2D points specified by src, and write
+ * the transformed points into the array of points specified by dst. The
+ * two arrays represent their "points" as pairs of floats [x, y].
+ *
+ * @param dst The array of dst points (x,y pairs)
+ * @param dstIndex The index of the first [x,y] pair of dst floats
+ * @param src The array of src points (x,y pairs)
+ * @param srcIndex The index of the first [x,y] pair of src floats
+ * @param pointCount The number of points (x,y pairs) to transform
+ */
+ public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
+ int pointCount) {
+ checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
+ native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
+ pointCount, true);
+ }
+
+ /**
+ * Apply this matrix to the array of 2D vectors specified by src, and write
+ * the transformed vectors into the array of vectors specified by dst. The
+ * two arrays represent their "vectors" as pairs of floats [x, y].
+ *
+ * @param dst The array of dst vectors (x,y pairs)
+ * @param dstIndex The index of the first [x,y] pair of dst floats
+ * @param src The array of src vectors (x,y pairs)
+ * @param srcIndex The index of the first [x,y] pair of src floats
+ * @param vectorCount The number of vectors (x,y pairs) to transform
+ */
+ public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
+ int vectorCount) {
+ checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
+ native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
+ vectorCount, false);
+ }
+
+ /**
+ * Apply this matrix to the array of 2D points specified by src, and write
+ * the transformed points into the array of points specified by dst. The
+ * two arrays represent their "points" as pairs of floats [x, y].
+ *
+ * @param dst The array of dst points (x,y pairs)
+ * @param src The array of src points (x,y pairs)
+ */
+ public void mapPoints(float[] dst, float[] src) {
+ if (dst.length != src.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ mapPoints(dst, 0, src, 0, dst.length >> 1);
+ }
+
+ /**
+ * Apply this matrix to the array of 2D vectors specified by src, and write
+ * the transformed vectors into the array of vectors specified by dst. The
+ * two arrays represent their "vectors" as pairs of floats [x, y].
+ *
+ * @param dst The array of dst vectors (x,y pairs)
+ * @param src The array of src vectors (x,y pairs)
+ */
+ public void mapVectors(float[] dst, float[] src) {
+ if (dst.length != src.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ mapVectors(dst, 0, src, 0, dst.length >> 1);
+ }
+
+ /**
+ * Apply this matrix to the array of 2D points, and write the transformed
+ * points back into the array
+ *
+ * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
+ */
+ public void mapPoints(float[] pts) {
+ mapPoints(pts, 0, pts, 0, pts.length >> 1);
+ }
+
+ /**
+ * Apply this matrix to the array of 2D vectors, and write the transformed
+ * vectors back into the array.
+ * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
+ */
+ public void mapVectors(float[] vecs) {
+ mapVectors(vecs, 0, vecs, 0, vecs.length >> 1);
+ }
+
+ /**
+ * Apply this matrix to the src rectangle, and write the transformed
+ * rectangle into dst. This is accomplished by transforming the 4 corners of
+ * src, and then setting dst to the bounds of those points.
+ *
+ * @param dst Where the transformed rectangle is written.
+ * @param src The original rectangle to be transformed.
+ * @return the result of calling rectStaysRect()
+ */
+ public boolean mapRect(RectF dst, RectF src) {
+ if (dst == null || src == null) {
+ throw new NullPointerException();
+ }
+ return native_mapRect(native_instance, dst, src);
+ }
+
+ /**
+ * Apply this matrix to the rectangle, and write the transformed rectangle
+ * back into it. This is accomplished by transforming the 4 corners of rect,
+ * and then setting it to the bounds of those points
+ *
+ * @param rect The rectangle to transform.
+ * @return the result of calling rectStaysRect()
+ */
+ public boolean mapRect(RectF rect) {
+ return mapRect(rect, rect);
+ }
+
+ /**
+ * Return the mean radius of a circle after it has been mapped by
+ * this matrix. NOTE: in perspective this value assumes the circle
+ * has its center at the origin.
+ */
+ public float mapRadius(float radius) {
+ return native_mapRadius(native_instance, radius);
+ }
+
+ /** Copy 9 values from the matrix into the array.
+ */
+ public void getValues(float[] values) {
+ if (values.length < 9) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_getValues(native_instance, values);
+ }
+
+ /** Copy 9 values from the array into the matrix.
+ Depending on the implementation of Matrix, these may be
+ transformed into 16.16 integers in the Matrix, such that
+ a subsequent call to getValues() will not yield exactly
+ the same values.
+ */
+ public void setValues(float[] values) {
+ if (values.length < 9) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_setValues(native_instance, values);
+ }
+
+ public String toString() {
+ return "Matrix{" + toShortString() + "}";
+
+ }
+
+ public String toShortString() {
+ float[] values = new float[9];
+ getValues(values);
+ return "[" +
+ values[0] + ", " + values[1] + ", " + values[2] + "][" +
+ values[3] + ", " + values[4] + ", " + values[5] + "][" +
+ values[6] + ", " + values[7] + ", " + values[8] + "]";
+
+ }
+
+ protected void finalize() throws Throwable {
+ finalizer(native_instance);
+ }
+
+ /*package*/ final int ni() {
+ return native_instance;
+ }
+
+ private static native int native_create(int native_src_or_zero);
+ private static native boolean native_isIdentity(int native_object);
+ private static native boolean native_rectStaysRect(int native_object);
+ private static native void native_reset(int native_object);
+ private static native void native_set(int native_object, int other);
+ private static native void native_setTranslate(int native_object,
+ float dx, float dy);
+ private static native void native_setScale(int native_object,
+ float sx, float sy, float px, float py);
+ private static native void native_setScale(int native_object,
+ float sx, float sy);
+ private static native void native_setRotate(int native_object,
+ float degrees, float px, float py);
+ private static native void native_setRotate(int native_object,
+ float degrees);
+ private static native void native_setSinCos(int native_object,
+ float sinValue, float cosValue, float px, float py);
+ private static native void native_setSinCos(int native_object,
+ float sinValue, float cosValue);
+ private static native void native_setSkew(int native_object,
+ float kx, float ky, float px, float py);
+ private static native void native_setSkew(int native_object,
+ float kx, float ky);
+ private static native boolean native_setConcat(int native_object,
+ int a, int b);
+ private static native boolean native_preTranslate(int native_object,
+ float dx, float dy);
+ private static native boolean native_preScale(int native_object,
+ float sx, float sy, float px, float py);
+ private static native boolean native_preScale(int native_object,
+ float sx, float sy);
+ private static native boolean native_preRotate(int native_object,
+ float degrees, float px, float py);
+ private static native boolean native_preRotate(int native_object,
+ float degrees);
+ private static native boolean native_preSkew(int native_object,
+ float kx, float ky, float px, float py);
+ private static native boolean native_preSkew(int native_object,
+ float kx, float ky);
+ private static native boolean native_preConcat(int native_object,
+ int other_matrix);
+ private static native boolean native_postTranslate(int native_object,
+ float dx, float dy);
+ private static native boolean native_postScale(int native_object,
+ float sx, float sy, float px, float py);
+ private static native boolean native_postScale(int native_object,
+ float sx, float sy);
+ private static native boolean native_postRotate(int native_object,
+ float degrees, float px, float py);
+ private static native boolean native_postRotate(int native_object,
+ float degrees);
+ private static native boolean native_postSkew(int native_object,
+ float kx, float ky, float px, float py);
+ private static native boolean native_postSkew(int native_object,
+ float kx, float ky);
+ private static native boolean native_postConcat(int native_object,
+ int other_matrix);
+ private static native boolean native_setRectToRect(int native_object,
+ RectF src, RectF dst, int stf);
+ private static native boolean native_setPolyToPoly(int native_object,
+ float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
+ private static native boolean native_invert(int native_object, int inverse);
+ private static native void native_mapPoints(int native_object,
+ float[] dst, int dstIndex, float[] src, int srcIndex,
+ int ptCount, boolean isPts);
+ private static native boolean native_mapRect(int native_object,
+ RectF dst, RectF src);
+ private static native float native_mapRadius(int native_object,
+ float radius);
+ private static native void native_getValues(int native_object,
+ float[] values);
+ private static native void native_setValues(int native_object,
+ float[] values);
+ private static native boolean native_equals(int native_a, int native_b);
+ private static native void finalizer(int native_instance);
+}
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
new file mode 100644
index 0000000..95e9946
--- /dev/null
+++ b/graphics/java/android/graphics/Movie.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2006 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.io.InputStream;
+import java.io.FileInputStream;
+
+public class Movie {
+ private final int mNativeMovie;
+
+ private Movie(int nativeMovie) {
+ if (nativeMovie == 0) {
+ throw new RuntimeException("native movie creation failed");
+ }
+ mNativeMovie = nativeMovie;
+ }
+
+ public native int width();
+ public native int height();
+ public native boolean isOpaque();
+ public native int duration();
+
+ public native boolean setTime(int relativeMilliseconds);
+
+ public native void draw(Canvas canvas, float x, float y, Paint paint);
+
+ public void draw(Canvas canvas, float x, float y) {
+ draw(canvas, x, y, null);
+ }
+
+ public static native Movie decodeStream(InputStream is);
+ public static native Movie decodeByteArray(byte[] data, int offset,
+ int length);
+
+ public static Movie decodeFile(String pathName) {
+ InputStream is;
+ try {
+ is = new FileInputStream(pathName);
+ }
+ catch (java.io.FileNotFoundException e) {
+ return null;
+ }
+ return decodeTempStream(is);
+ }
+
+ private static Movie decodeTempStream(InputStream is) {
+ Movie moov = null;
+ try {
+ moov = decodeStream(is);
+ is.close();
+ }
+ catch (java.io.IOException e) {
+ /* do nothing.
+ If the exception happened on open, moov will be null.
+ If it happened on close, moov is still valid.
+ */
+ }
+ return moov;
+ }
+}
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
new file mode 100644
index 0000000..cabd848
--- /dev/null
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2006 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;
+
+
+/**
+ * The NinePatch class permits drawing a bitmap in nine sections.
+ * The four corners are unscaled; the four edges are scaled in one axis,
+ * and the middle is scaled in both axes. Normally, the middle is
+ * transparent so that the patch can provide a selection about a rectangle.
+ * Essentially, it allows the creation of custom graphics that will scale the
+ * way that you define, when content added within the image exceeds the normal
+ * bounds of the graphic. For a thorough explanation of a NinePatch image,
+ * read the discussion in the
+ * <a href="{@docRoot}reference/available-resources.html#ninepatch">Available
+ * Resource Types</a> document.
+ * <p>
+ * The <a href="{@docRoot}reference/draw9patch.html">Draw 9-patch</a>
+ * tool offers an extremely handy way to create your NinePatch images,
+ * using a WYSIWYG graphics editor.
+ * </p>
+ */
+public class NinePatch {
+ /**
+ * Create a drawable projection from a bitmap to nine patches.
+ *
+ * @param bitmap The bitmap describing the patches.
+ * @param chunk The 9-patch data chunk describing how the underlying
+ * bitmap is split apart and drawn.
+ * @param srcName The name of the source for the bitmap. Might be null.
+ */
+ public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
+ mBitmap = bitmap;
+ mChunk = chunk;
+ mSrcName = srcName;
+ validateNinePatchChunk(mBitmap.ni(), chunk);
+ }
+
+ public void setPaint(Paint p) {
+ mPaint = p;
+ }
+
+ /**
+ * Draw a bitmap to nine patches.
+ *
+ * @param canvas A container for the current matrix and clip used to draw the bitmap.
+ * @param location Where to draw the bitmap.
+ */
+ public void draw(Canvas canvas, RectF location) {
+ nativeDraw(canvas.mNativeCanvas, location,
+ mBitmap.ni(), mChunk,
+ mPaint != null ? mPaint.mNativePaint : 0);
+ }
+
+ /**
+ * Draw a bitmap to nine patches.
+ *
+ * @param canvas A container for the current matrix and clip used to draw the bitmap.
+ * @param location Where to draw the bitmap.
+ */
+ public void draw(Canvas canvas, Rect location) {
+ nativeDraw(canvas.mNativeCanvas, location,
+ mBitmap.ni(), mChunk,
+ mPaint != null ? mPaint.mNativePaint : 0);
+ }
+
+ /**
+ * Draw a bitmap to nine patches.
+ *
+ * @param canvas A container for the current matrix and clip used to draw the bitmap.
+ * @param location Where to draw the bitmap.
+ * @param paint The Paint to draw through.
+ */
+ public void draw(Canvas canvas, Rect location, Paint paint) {
+ nativeDraw(canvas.mNativeCanvas, location,
+ mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0);
+ }
+
+ public int getWidth() {
+ return mBitmap.getWidth();
+ }
+
+ public int getHeight() {
+ return mBitmap.getHeight();
+ }
+
+ public final boolean hasAlpha() {
+ return mBitmap.hasAlpha();
+ }
+
+ public final Region getTransparentRegion(Rect location) {
+ int r = nativeGetTransparentRegion(mBitmap.ni(), mChunk, location);
+ return r != 0 ? new Region(r) : null;
+ }
+
+ public native static boolean isNinePatchChunk(byte[] chunk);
+
+ private final Rect mRect = new Rect();
+ private final Bitmap mBitmap;
+ private final byte[] mChunk;
+ private Paint mPaint;
+ private String mSrcName; // Useful for debugging
+
+ private static native void validateNinePatchChunk(int bitmap, byte[] chunk);
+ private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
+ byte[] c, int paint_instance_or_null);
+ private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
+ byte[] c, int paint_instance_or_null);
+ private static native int nativeGetTransparentRegion(
+ int bitmap, byte[] chunk, Rect location);
+}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
new file mode 100644
index 0000000..6fac969
--- /dev/null
+++ b/graphics/java/android/graphics/Paint.java
@@ -0,0 +1,1314 @@
+/*
+ * Copyright (C) 2006 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 android.text.TextUtils;
+import android.text.SpannableString;
+import android.text.SpannedString;
+import android.text.GraphicsOperations;
+
+/**
+ * The Paint class holds the style and color information about how to draw
+ * geometries, text and bitmaps.
+ */
+public class Paint {
+
+ /*package*/ int mNativePaint;
+ private ColorFilter mColorFilter;
+ private MaskFilter mMaskFilter;
+ private PathEffect mPathEffect;
+ private Rasterizer mRasterizer;
+ private Shader mShader;
+ private Typeface mTypeface;
+ private Xfermode mXfermode;
+
+ private static final Style[] sStyleArray = {
+ Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
+ };
+ private static final Cap[] sCapArray = {
+ Cap.BUTT, Cap.ROUND, Cap.SQUARE
+ };
+ private static final Join[] sJoinArray = {
+ Join.MITER, Join.ROUND, Join.BEVEL
+ };
+ private static final Align[] sAlignArray = {
+ Align.LEFT, Align.CENTER, Align.RIGHT
+ };
+
+ /** bit mask for the flag enabling antialiasing */
+ public static final int ANTI_ALIAS_FLAG = 0x01;
+ /** bit mask for the flag enabling bitmap filtering */
+ public static final int FILTER_BITMAP_FLAG = 0x02;
+ /** bit mask for the flag enabling dithering */
+ public static final int DITHER_FLAG = 0x04;
+ /** bit mask for the flag enabling underline text */
+ public static final int UNDERLINE_TEXT_FLAG = 0x08;
+ /** bit mask for the flag enabling strike-thru text */
+ public static final int STRIKE_THRU_TEXT_FLAG = 0x10;
+ /** bit mask for the flag enabling fake-bold text */
+ public static final int FAKE_BOLD_TEXT_FLAG = 0x20;
+ /** bit mask for the flag enabling linear-text (no caching) */
+ public static final int LINEAR_TEXT_FLAG = 0x40;
+ /** bit mask for the flag enabling subpixel-text */
+ public static final int SUBPIXEL_TEXT_FLAG = 0x80;
+ /** bit mask for the flag enabling device kerning for text */
+ public static final int DEV_KERN_TEXT_FLAG = 0x100;
+
+ // we use this when we first create a paint
+ private static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG;
+
+ /**
+ * The Style specifies if the primitive being drawn is filled,
+ * stroked, or both (in the same color). The default is FILL.
+ */
+ public enum Style {
+ /**
+ * Geometry and text drawn with this style will be filled, ignoring all
+ * stroke-related settings in the paint.
+ */
+ FILL (0),
+ /**
+ * Geometry and text drawn with this style will be stroked, respecting
+ * the stroke-related fields on the paint.
+ */
+ STROKE (1),
+ /**
+ * Geometry and text drawn with this style will be both filled and
+ * stroked at the same time, respecting the stroke-related fields on
+ * the paint.
+ */
+ FILL_AND_STROKE (2);
+
+ Style(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * The Cap specifies the treatment for the beginning and ending of
+ * stroked lines and paths. The default is BUTT.
+ */
+ public enum Cap {
+ /**
+ * The stroke ends with the path, and does not project beyond it.
+ */
+ BUTT (0),
+ /**
+ * The stroke projects out as a square, with the center at the end
+ * of the path.
+ */
+ ROUND (1),
+ /**
+ * The stroke projects out as a semicircle, with the center at the
+ * end of the path.
+ */
+ SQUARE (2);
+
+ private Cap(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * The Join specifies the treatment where lines and curve segments
+ * join on a stroked path. The default is MITER.
+ */
+ public enum Join {
+ /**
+ * The outer edges of a join meet at a sharp angle
+ */
+ MITER (0),
+ /**
+ * The outer edges of a join meet in a circular arc.
+ */
+ ROUND (1),
+ /**
+ * The outer edges of a join meet with a straight line
+ */
+ BEVEL (2);
+
+ private Join(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Align specifies how drawText aligns its text relative to the
+ * [x,y] coordinates. The default is LEFT.
+ */
+ public enum Align {
+ /**
+ * The text is drawn to the right of the x,y origin
+ */
+ LEFT (0),
+ /**
+ * The text is drawn centered horizontally on the x,y origin
+ */
+ CENTER (1),
+ /**
+ * The text is drawn to the left of the x,y origin
+ */
+ RIGHT (2);
+
+ private Align(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Create a new paint with default settings.
+ */
+ public Paint() {
+ this(0);
+ }
+
+ /**
+ * Create a new paint with the specified flags. Use setFlags() to change
+ * these after the paint is created.
+ *
+ * @param flags initial flag bits, as if they were passed via setFlags().
+ */
+ public Paint(int flags) {
+ mNativePaint = native_init();
+ setFlags(flags | DEFAULT_PAINT_FLAGS);
+ }
+
+ /**
+ * Create a new paint, initialized with the attributes in the specified
+ * paint parameter.
+ *
+ * @param paint Existing paint used to initialized the attributes of the
+ * new paint.
+ */
+ public Paint(Paint paint) {
+ mNativePaint = native_initWithPaint(paint.mNativePaint);
+ }
+
+ /** Restores the paint to its default settings. */
+ public void reset() {
+ native_reset(mNativePaint);
+ setFlags(DEFAULT_PAINT_FLAGS);
+ }
+
+ /**
+ * Copy the fields from src into this paint. This is equivalent to calling
+ * get() on all of the src fields, and calling the corresponding set()
+ * methods on this.
+ */
+ public void set(Paint src) {
+ if (this != src) {
+ // copy over the native settings
+ native_set(mNativePaint, src.mNativePaint);
+ // copy over our java settings
+ mColorFilter = src.mColorFilter;
+ mMaskFilter = src.mMaskFilter;
+ mPathEffect = src.mPathEffect;
+ mRasterizer = src.mRasterizer;
+ mShader = src.mShader;
+ mTypeface = src.mTypeface;
+ mXfermode = src.mXfermode;
+ }
+ }
+
+ /**
+ * Return the paint's flags. Use the Flag enum to test flag values.
+ *
+ * @return the paint's flags (see enums ending in _Flag for bit masks)
+ */
+ public native int getFlags();
+
+ /**
+ * Set the paint's flags. Use the Flag enum to specific flag values.
+ *
+ * @param flags The new flag bits for the paint
+ */
+ public native void setFlags(int flags);
+
+ /**
+ * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
+ * AntiAliasing smooths out the edges of what is being drawn, but is has
+ * no impact on the interior of the shape. See setDither() and
+ * setFilterBitmap() to affect how colors are treated.
+ *
+ * @return true if the antialias bit is set in the paint's flags.
+ */
+ public final boolean isAntiAlias() {
+ return (getFlags() & ANTI_ALIAS_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit
+ * AntiAliasing smooths out the edges of what is being drawn, but is has
+ * no impact on the interior of the shape. See setDither() and
+ * setFilterBitmap() to affect how colors are treated.
+ *
+ * @param aa true to set the antialias bit in the flags, false to clear it
+ */
+ public native void setAntiAlias(boolean aa);
+
+ /**
+ * Helper for getFlags(), returning true if DITHER_FLAG bit is set
+ * Dithering affects how colors that are higher precision than the device
+ * are down-sampled. No dithering is generally faster, but higher precision
+ * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
+ * distribute the error inherent in this process, to reduce the visual
+ * artifacts.
+ *
+ * @return true if the dithering bit is set in the paint's flags.
+ */
+ public final boolean isDither() {
+ return (getFlags() & DITHER_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the DITHER_FLAG bit
+ * Dithering affects how colors that are higher precision than the device
+ * are down-sampled. No dithering is generally faster, but higher precision
+ * colors are just truncated down (e.g. 8888 -> 565). Dithering tries to
+ * distribute the error inherent in this process, to reduce the visual
+ * artifacts.
+ *
+ * @param dither true to set the dithering bit in flags, false to clear it
+ */
+ public native void setDither(boolean dither);
+
+ /**
+ * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
+ *
+ * @return true if the lineartext bit is set in the paint's flags
+ */
+ public final boolean isLinearText() {
+ return (getFlags() & LINEAR_TEXT_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the LINEAR_TEXT_FLAG bit
+ *
+ * @param linearText true to set the linearText bit in the paint's flags,
+ * false to clear it.
+ */
+ public native void setLinearText(boolean linearText);
+
+ /**
+ * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
+ *
+ * @return true if the subpixel bit is set in the paint's flags
+ */
+ public final boolean isSubpixelText() {
+ return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
+ *
+ * @param subpixelText true to set the subpixelText bit in the paint's
+ * flags, false to clear it.
+ */
+ public native void setSubpixelText(boolean subpixelText);
+
+ /**
+ * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
+ *
+ * @return true if the underlineText bit is set in the paint's flags.
+ */
+ public final boolean isUnderlineText() {
+ return (getFlags() & UNDERLINE_TEXT_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the UNDERLINE_TEXT_FLAG bit
+ *
+ * @param underlineText true to set the underlineText bit in the paint's
+ * flags, false to clear it.
+ */
+ public native void setUnderlineText(boolean underlineText);
+
+ /**
+ * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
+ *
+ * @return true if the strikeThruText bit is set in the paint's flags.
+ */
+ public final boolean isStrikeThruText() {
+ return (getFlags() & STRIKE_THRU_TEXT_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
+ *
+ * @param strikeThruText true to set the strikeThruText bit in the paint's
+ * flags, false to clear it.
+ */
+ public native void setStrikeThruText(boolean strikeThruText);
+
+ /**
+ * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
+ *
+ * @return true if the fakeBoldText bit is set in the paint's flags.
+ */
+ public final boolean isFakeBoldText() {
+ return (getFlags() & FAKE_BOLD_TEXT_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit
+ *
+ * @param fakeBoldText true to set the fakeBoldText bit in the paint's
+ * flags, false to clear it.
+ */
+ public native void setFakeBoldText(boolean fakeBoldText);
+
+ /**
+ * Whether or not the bitmap filter is activated.
+ * Filtering affects the sampling of bitmaps when they are transformed.
+ * Filtering does not affect how the colors in the bitmap are converted into
+ * device pixels. That is dependent on dithering and xfermodes.
+ *
+ * @see #setFilterBitmap(boolean) setFilterBitmap()
+ */
+ public final boolean isFilterBitmap() {
+ return (getFlags() & FILTER_BITMAP_FLAG) != 0;
+ }
+
+ /**
+ * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
+ * Filtering affects the sampling of bitmaps when they are transformed.
+ * Filtering does not affect how the colors in the bitmap are converted into
+ * device pixels. That is dependent on dithering and xfermodes.
+ *
+ * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
+ * flags, false to clear it.
+ */
+ public native void setFilterBitmap(boolean filter);
+
+ /**
+ * Return the paint's style, used for controlling how primitives'
+ * geometries are interpreted (except for drawBitmap, which always assumes
+ * FILL_STYLE).
+ *
+ * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
+ */
+ public Style getStyle() {
+ return sStyleArray[native_getStyle(mNativePaint)];
+ }
+
+ /**
+ * Set the paint's style, used for controlling how primitives'
+ * geometries are interpreted (except for drawBitmap, which always assumes
+ * Fill).
+ *
+ * @param style The new style to set in the paint
+ */
+ public void setStyle(Style style) {
+ native_setStyle(mNativePaint, style.nativeInt);
+ }
+
+ /**
+ * Return the paint's color. Note that the color is a 32bit value
+ * containing alpha as well as r,g,b. This 32bit value is not premultiplied,
+ * meaning that its alpha can be any value, regardless of the values of
+ * r,g,b. See the Color class for more details.
+ *
+ * @return the paint's color (and alpha).
+ */
+ public native int getColor();
+
+ /**
+ * Set the paint's color. Note that the color is an int containing alpha
+ * as well as r,g,b. This 32bit value is not premultiplied, meaning that
+ * its alpha can be any value, regardless of the values of r,g,b.
+ * See the Color class for more details.
+ *
+ * @param color The new color (including alpha) to set in the paint.
+ */
+ public native void setColor(int color);
+
+ /**
+ * Helper to getColor() that just returns the color's alpha value. This is
+ * the same as calling getColor() >>> 24. It always returns a value between
+ * 0 (completely transparent) and 255 (completely opaque).
+ *
+ * @return the alpha component of the paint's color.
+ */
+ public native int getAlpha();
+
+ /**
+ * Helper to setColor(), that only assigns the color's alpha value,
+ * leaving its r,g,b values unchanged. Results are undefined if the alpha
+ * value is outside of the range [0..255]
+ *
+ * @param a set the alpha component [0..255] of the paint's color.
+ */
+ public native void setAlpha(int a);
+
+ /**
+ * Helper to setColor(), that takes a,r,g,b and constructs the color int
+ *
+ * @param a The new alpha component (0..255) of the paint's color.
+ * @param r The new red component (0..255) of the paint's color.
+ * @param g The new green component (0..255) of the paint's color.
+ * @param b The new blue component (0..255) of the paint's color.
+ */
+ public void setARGB(int a, int r, int g, int b) {
+ setColor((a << 24) | (r << 16) | (g << 8) | b);
+ }
+
+ /**
+ * Return the width for stroking.
+ * <p />
+ * A value of 0 strokes in hairline mode.
+ * Hairlines always draws a single pixel independent of the canva's matrix.
+ *
+ * @return the paint's stroke width, used whenever the paint's style is
+ * Stroke or StrokeAndFill.
+ */
+ public native float getStrokeWidth();
+
+ /**
+ * Set the width for stroking.
+ * Pass 0 to stroke in hairline mode.
+ * Hairlines always draws a single pixel independent of the canva's matrix.
+ *
+ * @param width set the paint's stroke width, used whenever the paint's
+ * style is Stroke or StrokeAndFill.
+ */
+ public native void setStrokeWidth(float width);
+
+ /**
+ * Return the paint's stroke miter value. Used to control the behavior
+ * of miter joins when the joins angle is sharp.
+ *
+ * @return the paint's miter limit, used whenever the paint's style is
+ * Stroke or StrokeAndFill.
+ */
+ public native float getStrokeMiter();
+
+ /**
+ * Set the paint's stroke miter value. This is used to control the behavior
+ * of miter joins when the joins angle is sharp. This value must be >= 0.
+ *
+ * @param miter set the miter limit on the paint, used whenever the paint's
+ * style is Stroke or StrokeAndFill.
+ */
+ public native void setStrokeMiter(float miter);
+
+ /**
+ * Return the paint's Cap, controlling how the start and end of stroked
+ * lines and paths are treated.
+ *
+ * @return the line cap style for the paint, used whenever the paint's
+ * style is Stroke or StrokeAndFill.
+ */
+ public Cap getStrokeCap() {
+ return sCapArray[native_getStrokeCap(mNativePaint)];
+ }
+
+ /**
+ * Set the paint's Cap.
+ *
+ * @param cap set the paint's line cap style, used whenever the paint's
+ * style is Stroke or StrokeAndFill.
+ */
+ public void setStrokeCap(Cap cap) {
+ native_setStrokeCap(mNativePaint, cap.nativeInt);
+ }
+
+ /**
+ * Return the paint's stroke join type.
+ *
+ * @return the paint's Join.
+ */
+ public Join getStrokeJoin() {
+ return sJoinArray[native_getStrokeJoin(mNativePaint)];
+ }
+
+ /**
+ * Set the paint's Join.
+ *
+ * @param join set the paint's Join, used whenever the paint's style is
+ * Stroke or StrokeAndFill.
+ */
+ public void setStrokeJoin(Join join) {
+ native_setStrokeJoin(mNativePaint, join.nativeInt);
+ }
+
+ /**
+ * Applies any/all effects (patheffect, stroking) to src, returning the
+ * result in dst. The result is that drawing src with this paint will be
+ * the same as drawing dst with a default paint (at least from the
+ * geometric perspective).
+ *
+ * @param src input path
+ * @param dst output path (may be the same as src)
+ * @return true if the path should be filled, or false if it should be
+ * drawn with a hairline (width == 0)
+ */
+ public boolean getFillPath(Path src, Path dst) {
+ return native_getFillPath(mNativePaint, src.ni(), dst.ni());
+ }
+
+ /**
+ * Get the paint's shader object.
+ *
+ * @return the paint's shader (or null)
+ */
+ public Shader getShader() {
+ return mShader;
+ }
+
+ /**
+ * Set or clear the shader object.
+ * <p />
+ * Pass null to clear any previous shader.
+ * As a convenience, the parameter passed is also returned.
+ *
+ * @param shader May be null. the new shader to be installed in the paint
+ * @return shader
+ */
+ public Shader setShader(Shader shader) {
+ int shaderNative = 0;
+ if (shader != null)
+ shaderNative = shader.native_instance;
+ native_setShader(mNativePaint, shaderNative);
+ mShader = shader;
+ return shader;
+ }
+
+ /**
+ * Get the paint's colorfilter (maybe be null).
+ *
+ * @return the paint's colorfilter (maybe be null)
+ */
+ public ColorFilter getColorFilter() {
+ return mColorFilter;
+ }
+
+ /**
+ * Set or clear the paint's colorfilter, returning the parameter.
+ *
+ * @param filter May be null. The new filter to be installed in the paint
+ * @return filter
+ */
+ public ColorFilter setColorFilter(ColorFilter filter) {
+ int filterNative = 0;
+ if (filter != null)
+ filterNative = filter.native_instance;
+ native_setColorFilter(mNativePaint, filterNative);
+ mColorFilter = filter;
+ return filter;
+ }
+
+ /**
+ * Get the paint's xfermode object.
+ *
+ * @return the paint's xfermode (or null)
+ */
+ public Xfermode getXfermode() {
+ return mXfermode;
+ }
+
+ /**
+ * Set or clear the xfermode object.
+ * <p />
+ * Pass null to clear any previous xfermode.
+ * As a convenience, the parameter passed is also returned.
+ *
+ * @param xfermode May be null. The xfermode to be installed in the paint
+ * @return xfermode
+ */
+ public Xfermode setXfermode(Xfermode xfermode) {
+ int xfermodeNative = 0;
+ if (xfermode != null)
+ xfermodeNative = xfermode.native_instance;
+ native_setXfermode(mNativePaint, xfermodeNative);
+ mXfermode = xfermode;
+ return xfermode;
+ }
+
+ /**
+ * Get the paint's patheffect object.
+ *
+ * @return the paint's patheffect (or null)
+ */
+ public PathEffect getPathEffect() {
+ return mPathEffect;
+ }
+
+ /**
+ * Set or clear the patheffect object.
+ * <p />
+ * Pass null to clear any previous patheffect.
+ * As a convenience, the parameter passed is also returned.
+ *
+ * @param effect May be null. The patheffect to be installed in the paint
+ * @return effect
+ */
+ public PathEffect setPathEffect(PathEffect effect) {
+ int effectNative = 0;
+ if (effect != null) {
+ effectNative = effect.native_instance;
+ }
+ native_setPathEffect(mNativePaint, effectNative);
+ mPathEffect = effect;
+ return effect;
+ }
+
+ /**
+ * Get the paint's maskfilter object.
+ *
+ * @return the paint's maskfilter (or null)
+ */
+ public MaskFilter getMaskFilter() {
+ return mMaskFilter;
+ }
+
+ /**
+ * Set or clear the maskfilter object.
+ * <p />
+ * Pass null to clear any previous maskfilter.
+ * As a convenience, the parameter passed is also returned.
+ *
+ * @param maskfilter May be null. The maskfilter to be installed in the
+ * paint
+ * @return maskfilter
+ */
+ public MaskFilter setMaskFilter(MaskFilter maskfilter) {
+ int maskfilterNative = 0;
+ if (maskfilter != null) {
+ maskfilterNative = maskfilter.native_instance;
+ }
+ native_setMaskFilter(mNativePaint, maskfilterNative);
+ mMaskFilter = maskfilter;
+ return maskfilter;
+ }
+
+ /**
+ * Get the paint's typeface object.
+ * <p />
+ * The typeface object identifies which font to use when drawing or
+ * measuring text.
+ *
+ * @return the paint's typeface (or null)
+ */
+ public Typeface getTypeface() {
+ return mTypeface;
+ }
+
+ /**
+ * Set or clear the typeface object.
+ * <p />
+ * Pass null to clear any previous typeface.
+ * As a convenience, the parameter passed is also returned.
+ *
+ * @param typeface May be null. The typeface to be installed in the paint
+ * @return typeface
+ */
+ public Typeface setTypeface(Typeface typeface) {
+ int typefaceNative = 0;
+ if (typeface != null) {
+ typefaceNative = typeface.native_instance;
+ }
+ native_setTypeface(mNativePaint, typefaceNative);
+ mTypeface = typeface;
+ return typeface;
+ }
+
+ /**
+ * Get the paint's rasterizer (or null).
+ * <p />
+ * The raster controls/modifies how paths/text are turned into alpha masks.
+ *
+ * @return the paint's rasterizer (or null)
+ */
+ public Rasterizer getRasterizer() {
+ return mRasterizer;
+ }
+
+ /**
+ * Set or clear the rasterizer object.
+ * <p />
+ * Pass null to clear any previous rasterizer.
+ * As a convenience, the parameter passed is also returned.
+ *
+ * @param rasterizer May be null. The new rasterizer to be installed in
+ * the paint.
+ * @return rasterizer
+ */
+ public Rasterizer setRasterizer(Rasterizer rasterizer) {
+ int rasterizerNative = 0;
+ if (rasterizer != null) {
+ rasterizerNative = rasterizer.native_instance;
+ }
+ native_setRasterizer(mNativePaint, rasterizerNative);
+ mRasterizer = rasterizer;
+ return rasterizer;
+ }
+
+ /**
+ * Temporary API to expose layer drawing. This draws a shadow layer below
+ * the main layer, with the specified offset and color, and blur radius.
+ * If radius is 0, then the shadow layer is removed.
+ */
+ public native void setShadowLayer(float radius, float dx, float dy,
+ int color);
+
+ /**
+ * Temporary API to clear the shadow layer.
+ */
+ public void clearShadowLayer() {
+ setShadowLayer(0, 0, 0, 0);
+ }
+
+ /**
+ * Return the paint's Align value for drawing text. This controls how the
+ * text is positioned relative to its origin. LEFT align means that all of
+ * the text will be drawn to the right of its origin (i.e. the origin
+ * specifieds the LEFT edge of the text) and so on.
+ *
+ * @return the paint's Align value for drawing text.
+ */
+ public Align getTextAlign() {
+ return sAlignArray[native_getTextAlign(mNativePaint)];
+ }
+
+ /**
+ * Set the paint's text alignment. This controls how the
+ * text is positioned relative to its origin. LEFT align means that all of
+ * the text will be drawn to the right of its origin (i.e. the origin
+ * specifieds the LEFT edge of the text) and so on.
+ *
+ * @param align set the paint's Align value for drawing text.
+ */
+ public void setTextAlign(Align align) {
+ native_setTextAlign(mNativePaint, align.nativeInt);
+ }
+
+ /**
+ * Return the paint's text size.
+ *
+ * @return the paint's text size.
+ */
+ public native float getTextSize();
+
+ /**
+ * Set the paint's text size. This value must be > 0
+ *
+ * @param textSize set the paint's text size.
+ */
+ public native void setTextSize(float textSize);
+
+ /**
+ * Return the paint's horizontal scale factor for text. The default value
+ * is 1.0.
+ *
+ * @return the paint's scale factor in X for drawing/measuring text
+ */
+ public native float getTextScaleX();
+
+ /**
+ * Set the paint's horizontal scale factor for text. The default value
+ * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
+ * stretch the text narrower.
+ *
+ * @param scaleX set the paint's scale in X for drawing/measuring text.
+ */
+ public native void setTextScaleX(float scaleX);
+
+ /**
+ * Return the paint's horizontal skew factor for text. The default value
+ * is 0.
+ *
+ * @return the paint's skew factor in X for drawing text.
+ */
+ public native float getTextSkewX();
+
+ /**
+ * Set the paint's horizontal skew factor for text. The default value
+ * is 0. For approximating oblique text, use values around -0.25.
+ *
+ * @param skewX set the paint's skew factor in X for drawing text.
+ */
+ public native void setTextSkewX(float skewX);
+
+ /**
+ * Return the distance above (negative) the baseline (ascent) based on the
+ * current typeface and text size.
+ *
+ * @return the distance above (negative) the baseline (ascent) based on the
+ * current typeface and text size.
+ */
+ public native float ascent();
+
+ /**
+ * Return the distance below (positive) the baseline (descent) based on the
+ * current typeface and text size.
+ *
+ * @return the distance below (positive) the baseline (descent) based on
+ * the current typeface and text size.
+ */
+ public native float descent();
+
+ /**
+ * Class that describes the various metrics for a font at a given text size.
+ * Remember, Y values increase going down, so those values will be positive,
+ * and values that measure distances going up will be negative. This class
+ * is returned by getFontMetrics().
+ */
+ public static class FontMetrics {
+ /**
+ * The maximum distance above the baseline for the tallest glyph in
+ * the font at a given text size.
+ */
+ public float top;
+ /**
+ * The recommended distance above the baseline for singled spaced text.
+ */
+ public float ascent;
+ /**
+ * The recommended distance below the baseline for singled spaced text.
+ */
+ public float descent;
+ /**
+ * The maximum distance below the baseline for the lowest glyph in
+ * the font at a given text size.
+ */
+ public float bottom;
+ /**
+ * The recommended additional space to add between lines of text.
+ */
+ public float leading;
+ }
+
+ /**
+ * Return the font's recommended interline spacing, given the Paint's
+ * settings for typeface, textSize, etc. If metrics is not null, return the
+ * fontmetric values in it.
+ *
+ * @param metrics If this object is not null, its fields are filled with
+ * the appropriate values given the paint's text attributes.
+ * @return the font's recommended interline spacing.
+ */
+ public native float getFontMetrics(FontMetrics metrics);
+
+ /**
+ * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
+ * with it, returning the object.
+ */
+ public FontMetrics getFontMetrics() {
+ FontMetrics fm = new FontMetrics();
+ getFontMetrics(fm);
+ return fm;
+ }
+
+ /**
+ * Convenience method for callers that want to have FontMetrics values as
+ * integers.
+ */
+ public static class FontMetricsInt {
+ public int top;
+ public int ascent;
+ public int descent;
+ public int bottom;
+ public int leading;
+
+ @Override public String toString() {
+ return "FontMetricsInt: top=" + top + " ascent=" + ascent +
+ " descent=" + descent + " bottom=" + bottom +
+ " leading=" + leading;
+ }
+ }
+
+ /**
+ * Return the font's interline spacing, given the Paint's settings for
+ * typeface, textSize, etc. If metrics is not null, return the fontmetric
+ * values in it. Note: all values have been converted to integers from
+ * floats, in such a way has to make the answers useful for both spacing
+ * and clipping. If you want more control over the rounding, call
+ * getFontMetrics().
+ *
+ * @return the font's interline spacing.
+ */
+ public native int getFontMetricsInt(FontMetricsInt fmi);
+
+ public FontMetricsInt getFontMetricsInt() {
+ FontMetricsInt fm = new FontMetricsInt();
+ getFontMetricsInt(fm);
+ return fm;
+ }
+
+ /**
+ * Return the recommend line spacing based on the current typeface and
+ * text size.
+ *
+ * @return recommend line spacing based on the current typeface and
+ * text size.
+ */
+ public float getFontSpacing() {
+ return getFontMetrics(null);
+ }
+
+ /**
+ * Return the width of the text.
+ *
+ * @param text The text to measure
+ * @param index The index of the first character to start measuring
+ * @param count THe number of characters to measure, beginning with start
+ * @return The width of the text
+ */
+ public native float measureText(char[] text, int index, int count);
+
+ /**
+ * Return the width of the text.
+ *
+ * @param text The text to measure
+ * @param start The index of the first character to start measuring
+ * @param end 1 beyond the index of the last character to measure
+ * @return The width of the text
+ */
+ public native float measureText(String text, int start, int end);
+
+ /**
+ * Return the width of the text.
+ *
+ * @param text The text to measure
+ * @return The width of the text
+ */
+ public native float measureText(String text);
+
+ /**
+ * Return the width of the text.
+ *
+ * @param text The text to measure
+ * @param start The index of the first character to start measuring
+ * @param end 1 beyond the index of the last character to measure
+ * @return The width of the text
+ */
+ public float measureText(CharSequence text, int start, int end) {
+ if (text instanceof String) {
+ return measureText((String)text, start, end);
+ }
+ if (text instanceof SpannedString ||
+ text instanceof SpannableString) {
+ return measureText(text.toString(), start, end);
+ }
+ if (text instanceof GraphicsOperations) {
+ return ((GraphicsOperations)text).measureText(start, end, this);
+ }
+
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ TextUtils.getChars(text, start, end, buf, 0);
+ float result = measureText(buf, 0, end - start);
+ TemporaryBuffer.recycle(buf);
+ return result;
+ }
+
+ /**
+ * Measure the text, stopping early if the measured width exceeds maxWidth.
+ * Return the number of chars that were measured, and if measuredWidth is
+ * not null, return in it the actual width measured.
+ *
+ * @param text The text to measure
+ * @param index The offset into text to begin measuring at
+ * @param count The number of maximum number of entries to measure. If count
+ * is negative, then the characters before index are measured
+ * in reverse order. This allows for measuring the end of
+ * string.
+ * @param maxWidth The maximum width to accumulate.
+ * @param measuredWidth Optional. If not null, returns the actual width
+ * measured.
+ * @return The number of chars that were measured. Will always be <=
+ * abs(count).
+ */
+ public native int breakText(char[] text, int index, int count,
+ float maxWidth, float[] measuredWidth);
+
+ /**
+ * Measure the text, stopping early if the measured width exceeds maxWidth.
+ * Return the number of chars that were measured, and if measuredWidth is
+ * not null, return in it the actual width measured.
+ *
+ * @param text The text to measure
+ * @param start The offset into text to begin measuring at
+ * @param end The end of the text slice to measure.
+ * @param measureForwards If true, measure forwards, starting at start.
+ * Otherwise, measure backwards, starting with end.
+ * @param maxWidth The maximum width to accumulate.
+ * @param measuredWidth Optional. If not null, returns the actual width
+ * measured.
+ * @return The number of chars that were measured. Will always be <=
+ * abs(end - start).
+ */
+ public int breakText(CharSequence text, int start, int end,
+ boolean measureForwards,
+ float maxWidth, float[] measuredWidth) {
+ if (start == 0 && text instanceof String && end == text.length()) {
+ return breakText((String) text, measureForwards, maxWidth,
+ measuredWidth);
+ }
+
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ int result;
+
+ TextUtils.getChars(text, start, end, buf, 0);
+
+ if (measureForwards) {
+ result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
+ } else {
+ result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
+ }
+
+ TemporaryBuffer.recycle(buf);
+ return result;
+ }
+
+ /**
+ * Measure the text, stopping early if the measured width exceeds maxWidth.
+ * Return the number of chars that were measured, and if measuredWidth is
+ * not null, return in it the actual width measured.
+ *
+ * @param text The text to measure
+ * @param measureForwards If true, measure forwards, starting at index.
+ * Otherwise, measure backwards, starting with the
+ * last character in the string.
+ * @param maxWidth The maximum width to accumulate.
+ * @param measuredWidth Optional. If not null, returns the actual width
+ * measured.
+ * @return The number of chars that were measured. Will always be <=
+ * abs(count).
+ */
+ public native int breakText(String text, boolean measureForwards,
+ float maxWidth, float[] measuredWidth);
+
+ /**
+ * Return the advance widths for the characters in the string.
+ *
+ * @param text The text to measure
+ * @param index The index of the first char to to measure
+ * @param count The number of chars starting with index to measure
+ * @param widths array to receive the advance widths of the characters.
+ * Must be at least a large as count.
+ * @return the actual number of widths returned.
+ */
+ public int getTextWidths(char[] text, int index, int count,
+ float[] widths) {
+ if ((index | count) < 0 || index + count > text.length
+ || count > widths.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return native_getTextWidths(mNativePaint, text, index, count, widths);
+ }
+
+ /**
+ * Return the advance widths for the characters in the string.
+ *
+ * @param text The text to measure
+ * @param start The index of the first char to to measure
+ * @param end The end of the text slice to measure
+ * @param widths array to receive the advance widths of the characters.
+ * Must be at least a large as (end - start).
+ * @return the actual number of widths returned.
+ */
+ public int getTextWidths(CharSequence text, int start, int end,
+ float[] widths) {
+ if (text instanceof String) {
+ return getTextWidths((String) text, start, end, widths);
+ }
+ if (text instanceof SpannedString ||
+ text instanceof SpannableString) {
+ return getTextWidths(text.toString(), start, end, widths);
+ }
+ if (text instanceof GraphicsOperations) {
+ return ((GraphicsOperations) text).getTextWidths(start, end,
+ widths, this);
+ }
+
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ TextUtils.getChars(text, start, end, buf, 0);
+ int result = getTextWidths(buf, 0, end - start, widths);
+ TemporaryBuffer.recycle(buf);
+ return result;
+ }
+
+ /**
+ * Return the advance widths for the characters in the string.
+ *
+ * @param text The text to measure
+ * @param start The index of the first char to to measure
+ * @param end The end of the text slice to measure
+ * @param widths array to receive the advance widths of the characters.
+ * Must be at least a large as the text.
+ * @return the number of unichars in the specified text.
+ */
+ public int getTextWidths(String text, int start, int end, float[] widths) {
+ if ((start | end | (end - start) | (text.length() - end)) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (end - start > widths.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return native_getTextWidths(mNativePaint, text, start, end, widths);
+ }
+
+ /**
+ * Return the advance widths for the characters in the string.
+ *
+ * @param text The text to measure
+ * @param widths array to receive the advance widths of the characters.
+ * Must be at least a large as the text.
+ * @return the number of unichars in the specified text.
+ */
+ public int getTextWidths(String text, float[] widths) {
+ return getTextWidths(text, 0, text.length(), widths);
+ }
+
+ /**
+ * Return the path (outline) for the specified text.
+ * Note: just like Canvas.drawText, this will respect the Align setting in
+ * the paint.
+ *
+ * @param text The text to retrieve the path from
+ * @param index The index of the first character in text
+ * @param count The number of characterss starting with index
+ * @param x The x coordinate of the text's origin
+ * @param y The y coordinate of the text's origin
+ * @param path The path to receive the data describing the text. Must
+ * be allocated by the caller.
+ */
+ public void getTextPath(char[] text, int index, int count,
+ float x, float y, Path path) {
+ if ((index | count) < 0 || index + count > text.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
+ }
+
+ /**
+ * Return the path (outline) for the specified text.
+ * Note: just like Canvas.drawText, this will respect the Align setting
+ * in the paint.
+ *
+ * @param text The text to retrieve the path from
+ * @param start The first character in the text
+ * @param end 1 past the last charcter in the text
+ * @param x The x coordinate of the text's origin
+ * @param y The y coordinate of the text's origin
+ * @param path The path to receive the data describing the text. Must
+ * be allocated by the caller.
+ */
+ public void getTextPath(String text, int start, int end,
+ float x, float y, Path path) {
+ if ((start | end | (end - start) | (text.length() - end)) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ native_getTextPath(mNativePaint, text, start, end, x, y, path.ni());
+ }
+
+ /**
+ * Return in bounds (allocated by the caller) the smallest rectangle that
+ * encloses all of the characters, with an implied origin at (0,0).
+ *
+ * @param text String to measure and return its bounds
+ * @param start Index of the first char in the string to measure
+ * @param end 1 past the last char in the string measure
+ * @param bounds Returns the unioned bounds of all the text. Must be
+ * allocated by the caller.
+ */
+ public void getTextBounds(String text, int start, int end, Rect bounds) {
+ if ((start | end | (end - start) | (text.length() - end)) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (bounds == null) {
+ throw new NullPointerException("need bounds Rect");
+ }
+ nativeGetStringBounds(mNativePaint, text, start, end, bounds);
+ }
+
+ /**
+ * Return in bounds (allocated by the caller) the smallest rectangle that
+ * encloses all of the characters, with an implied origin at (0,0).
+ *
+ * @param text Array of chars to measure and return their unioned bounds
+ * @param index Index of the first char in the array to measure
+ * @param count The number of chars, beginning at index, to measure
+ * @param bounds Returns the unioned bounds of all the text. Must be
+ * allocated by the caller.
+ */
+ public void getTextBounds(char[] text, int index, int count, Rect bounds) {
+ if ((index | count) < 0 || index + count > text.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ if (bounds == null) {
+ throw new NullPointerException("need bounds Rect");
+ }
+ nativeGetCharArrayBounds(mNativePaint, text, index, count, bounds);
+ }
+
+ protected void finalize() throws Throwable {
+ finalizer(mNativePaint);
+ }
+
+ private static native int native_init();
+ private static native int native_initWithPaint(int paint);
+ private static native void native_reset(int native_object);
+ private static native void native_set(int native_dst, int native_src);
+ private static native int native_getStyle(int native_object);
+ private static native void native_setStyle(int native_object, int style);
+ private static native int native_getStrokeCap(int native_object);
+ private static native void native_setStrokeCap(int native_object, int cap);
+ private static native int native_getStrokeJoin(int native_object);
+ private static native void native_setStrokeJoin(int native_object,
+ int join);
+ private static native boolean native_getFillPath(int native_object,
+ int src, int dst);
+ private static native int native_setShader(int native_object, int shader);
+ private static native int native_setColorFilter(int native_object,
+ int filter);
+ private static native int native_setXfermode(int native_object,
+ int xfermode);
+ private static native int native_setPathEffect(int native_object,
+ int effect);
+ private static native int native_setMaskFilter(int native_object,
+ int maskfilter);
+ private static native int native_setTypeface(int native_object,
+ int typeface);
+ private static native int native_setRasterizer(int native_object,
+ int rasterizer);
+
+ private static native int native_getTextAlign(int native_object);
+ private static native void native_setTextAlign(int native_object,
+ int align);
+
+ private static native float native_getFontMetrics(int native_paint,
+ FontMetrics metrics);
+ private static native int native_getTextWidths(int native_object,
+ char[] text, int index, int count, float[] widths);
+ private static native int native_getTextWidths(int native_object,
+ String text, int start, int end, float[] widths);
+ private static native void native_getTextPath(int native_object,
+ char[] text, int index, int count, float x, float y, int path);
+ private static native void native_getTextPath(int native_object,
+ String text, int start, int end, float x, float y, int path);
+ private static native void nativeGetStringBounds(int nativePaint,
+ String text, int start, int end, Rect bounds);
+ private static native void nativeGetCharArrayBounds(int nativePaint,
+ char[] text, int index, int count, Rect bounds);
+ private static native void finalizer(int nativePaint);
+}
+
diff --git a/graphics/java/android/graphics/PaintFlagsDrawFilter.java b/graphics/java/android/graphics/PaintFlagsDrawFilter.java
new file mode 100644
index 0000000..0f0d03d
--- /dev/null
+++ b/graphics/java/android/graphics/PaintFlagsDrawFilter.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+public class PaintFlagsDrawFilter extends DrawFilter {
+
+ /**
+ * Subclass of DrawFilter that affects every paint by first clearing
+ * the specified clearBits in the paint's flags, and then setting the
+ * specified setBits in the paint's flags.
+ *
+ * @param clearBits These bits will be cleared in the paint's flags
+ * @param setBits These bits will be set in the paint's flags
+ */
+ public PaintFlagsDrawFilter(int clearBits, int setBits) {
+ // our native constructor can return 0, if the specified bits
+ // are effectively a no-op
+ mNativeInt = nativeConstructor(clearBits, setBits);
+ }
+
+ private static native int nativeConstructor(int clearBits, int setBits);
+}
+
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
new file mode 100644
index 0000000..c3f63d7
--- /dev/null
+++ b/graphics/java/android/graphics/Path.java
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2006 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;
+
+/**
+ * The Path class encapsulates compound (multiple contour) geometric paths
+ * consisting of straight line segments, quadratic curves, and cubic curves.
+ * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
+ * (based on the paint's Style), or it can be used for clipping or to draw
+ * text on a path.
+ */
+public class Path {
+
+ /**
+ * Create an empty path
+ */
+ public Path() {
+ mNativePath = init1();
+ }
+
+ /**
+ * Create a new path, copying the contents from the src path.
+ *
+ * @param src The path to copy from when initializing the new path
+ */
+ public Path(Path src) {
+ int valNative = 0;
+ if (src != null) {
+ valNative = src.mNativePath;
+ }
+ mNativePath = init2(valNative);
+ }
+
+ /**
+ * Clear any lines and curves from the path, making it empty.
+ * This does NOT change the fill-type setting.
+ */
+ public void reset() {
+ native_reset(mNativePath);
+ }
+
+ /**
+ * Rewinds the path: clears any lines and curves from the path but
+ * keeps the internal data structure for faster reuse.
+ */
+ public void rewind() {
+ native_rewind(mNativePath);
+ }
+
+ /** Replace the contents of this with the contents of src.
+ */
+ public void set(Path src) {
+ if (this != src) {
+ native_set(mNativePath, src.mNativePath);
+ }
+ }
+
+ /** Enum for the ways a path may be filled
+ */
+ public enum FillType {
+ // these must match the values in SkPath.h
+ WINDING (0),
+ EVEN_ODD (1),
+ INVERSE_WINDING (2),
+ INVERSE_EVEN_ODD(3);
+
+ FillType(int ni) {
+ nativeInt = ni;
+ }
+ final int nativeInt;
+ }
+
+ // these must be in the same order as their native values
+ private static final FillType[] sFillTypeArray = {
+ FillType.WINDING,
+ FillType.EVEN_ODD,
+ FillType.INVERSE_WINDING,
+ FillType.INVERSE_EVEN_ODD
+ };
+
+ /**
+ * Return the path's fill type. This defines how "inside" is
+ * computed. The default value is WINDING.
+ *
+ * @return the path's fill type
+ */
+ public FillType getFillType() {
+ return sFillTypeArray[native_getFillType(mNativePath)];
+ }
+
+ /**
+ * Set the path's fill type. This defines how "inside" is computed.
+ *
+ * @param ft The new fill type for this path
+ */
+ public void setFillType(FillType ft) {
+ native_setFillType(mNativePath, ft.nativeInt);
+ }
+
+ /**
+ * Returns true if the filltype is one of the INVERSE variants
+ *
+ * @return true if the filltype is one of the INVERSE variants
+ */
+ public boolean isInverseFillType() {
+ final int ft = native_getFillType(mNativePath);
+ return (ft & 2) != 0;
+ }
+
+ /**
+ * Toggles the INVERSE state of the filltype
+ */
+ public void toggleInverseFillType() {
+ int ft = native_getFillType(mNativePath);
+ ft ^= 2;
+ native_setFillType(mNativePath, ft);
+ }
+
+ /**
+ * Returns true if the path is empty (contains no lines or curves)
+ *
+ * @return true if the path is empty (contains no lines or curves)
+ */
+ public boolean isEmpty() {
+ return native_isEmpty(mNativePath);
+ }
+
+ /**
+ * Returns true if the path specifies a rectangle. If so, and if rect is
+ * not null, set rect to the bounds of the path. If the path does not
+ * specify a rectangle, return false and ignore rect.
+ *
+ * @param rect If not null, returns the bounds of the path if it specifies
+ * a rectangle
+ * @return true if the path specifies a rectangle
+ */
+ public boolean isRect(RectF rect) {
+ return native_isRect(mNativePath, rect);
+ }
+
+ /**
+ * Compute the bounds of the path, and write the answer into bounds. If the
+ * path contains 0 or 1 points, the bounds is set to (0,0,0,0)
+ *
+ * @param bounds Returns the computed bounds of the path
+ * @param exact If true, return the exact (but slower) bounds, else return
+ * just the bounds of all control points
+ */
+ public void computeBounds(RectF bounds, boolean exact) {
+ // 1-exact, 0-fast correspond to the values in SkPath.h
+ native_computeBounds(mNativePath, bounds, exact ? 1 : 0);
+ }
+
+ /**
+ * Hint to the path to prepare for adding more points. This can allow the
+ * path to more efficiently allocate its storage.
+ *
+ * @param extraPtCount The number of extra points that may be added to this
+ * path
+ */
+ public void incReserve(int extraPtCount) {
+ native_incReserve(mNativePath, extraPtCount);
+ }
+
+ /**
+ * Set the beginning of the next contour to the point (x,y).
+ *
+ * @param x The x-coordinate of the start of a new contour
+ * @param y The y-coordinate of the start of a new contour
+ */
+ public void moveTo(float x, float y) {
+ native_moveTo(mNativePath, x, y);
+ }
+
+ /**
+ * Set the beginning of the next contour relative to the last point on the
+ * previous contour. If there is no previous contour, this is treated the
+ * same as moveTo().
+ *
+ * @param dx The amount to add to the x-coordinate of the end of the
+ * previous contour, to specify the start of a new contour
+ * @param dy The amount to add to the y-coordinate of the end of the
+ * previous contour, to specify the start of a new contour
+ */
+ public void rMoveTo(float dx, float dy) {
+ native_rMoveTo(mNativePath, dx, dy);
+ }
+
+ /**
+ * Add a line from the last point to the specified point (x,y).
+ * If no moveTo() call has been made for this contour, the first point is
+ * automatically set to (0,0).
+ *
+ * @param x The x-coordinate of the end of a line
+ * @param y The y-coordinate of the end of a line
+ */
+ public void lineTo(float x, float y) {
+ native_lineTo(mNativePath, x, y);
+ }
+
+ /**
+ * Same as lineTo, but the coordinates are considered relative to the last
+ * point on this contour. If there is no previous point, then a moveTo(0,0)
+ * is inserted automatically.
+ *
+ * @param dx The amount to add to the x-coordinate of the previous point on
+ * this contour, to specify a line
+ * @param dy The amount to add to the y-coordinate of the previous point on
+ * this contour, to specify a line
+ */
+ public void rLineTo(float dx, float dy) {
+ native_rLineTo(mNativePath, dx, dy);
+ }
+
+ /**
+ * Add a quadratic bezier from the last point, approaching control point
+ * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
+ * this contour, the first point is automatically set to (0,0).
+ *
+ * @param x1 The x-coordinate of the control point on a quadratic curve
+ * @param y1 The y-coordinate of the control point on a quadratic curve
+ * @param x2 The x-coordinate of the end point on a quadratic curve
+ * @param y2 The y-coordinate of the end point on a quadratic curve
+ */
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ native_quadTo(mNativePath, x1, y1, x2, y2);
+ }
+
+ /**
+ * Same as quadTo, but the coordinates are considered relative to the last
+ * point on this contour. If there is no previous point, then a moveTo(0,0)
+ * is inserted automatically.
+ *
+ * @param dx1 The amount to add to the x-coordinate of the last point on
+ * this contour, for the control point of a quadratic curve
+ * @param dy1 The amount to add to the y-coordinate of the last point on
+ * this contour, for the control point of a quadratic curve
+ * @param dx2 The amount to add to the x-coordinate of the last point on
+ * this contour, for the end point of a quadratic curve
+ * @param dy2 The amount to add to the y-coordinate of the last point on
+ * this contour, for the end point of a quadratic curve
+ */
+ public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
+ native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2);
+ }
+
+ /**
+ * Add a cubic bezier from the last point, approaching control points
+ * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
+ * made for this contour, the first point is automatically set to (0,0).
+ *
+ * @param x1 The x-coordinate of the 1st control point on a cubic curve
+ * @param y1 The y-coordinate of the 1st control point on a cubic curve
+ * @param x2 The x-coordinate of the 2nd control point on a cubic curve
+ * @param y2 The y-coordinate of the 2nd control point on a cubic curve
+ * @param x3 The x-coordinate of the end point on a cubic curve
+ * @param y3 The y-coordinate of the end point on a cubic curve
+ */
+ public void cubicTo(float x1, float y1, float x2, float y2,
+ float x3, float y3) {
+ native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
+ }
+
+ /**
+ * Same as cubicTo, but the coordinates are considered relative to the
+ * current point on this contour. If there is no previous point, then a
+ * moveTo(0,0) is inserted automatically.
+ */
+ public void rCubicTo(float x1, float y1, float x2, float y2,
+ float x3, float y3) {
+ native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
+ }
+
+ /**
+ * Append the specified arc to the path as a new contour. If the start of
+ * the path is different from the path's current last point, then an
+ * automatic lineTo() is added to connect the current contour to the
+ * start of the arc. However, if the path is empty, then we call moveTo()
+ * with the first point of the arc. The sweep angle is tread mod 360.
+ *
+ * @param oval The bounds of oval defining shape and size of the arc
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
+ * mod 360.
+ * @param forceMoveTo If true, always begin a new contour with the arc
+ */
+ public void arcTo(RectF oval, float startAngle, float sweepAngle,
+ boolean forceMoveTo) {
+ native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
+ }
+
+ /**
+ * Append the specified arc to the path as a new contour. If the start of
+ * the path is different from the path's current last point, then an
+ * automatic lineTo() is added to connect the current contour to the
+ * start of the arc. However, if the path is empty, then we call moveTo()
+ * with the first point of the arc.
+ *
+ * @param oval The bounds of oval defining shape and size of the arc
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ */
+ public void arcTo(RectF oval, float startAngle, float sweepAngle) {
+ native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
+ }
+
+ /**
+ * Close the current contour. If the current point is not equal to the
+ * first point of the contour, a line segment is automatically added.
+ */
+ public void close() {
+ native_close(mNativePath);
+ }
+
+ /**
+ * Specifies how closed shapes (e.g. rects, ovals) are oriented when they
+ * are added to a path.
+ */
+ public enum Direction {
+ /** clockwise */
+ CW (0), // must match enum in SkPath.h
+ /** counter-clockwise */
+ CCW (1); // must match enum in SkPath.h
+
+ Direction(int ni) {
+ nativeInt = ni;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Add a closed rectangle contour to the path
+ *
+ * @param rect The rectangle to add as a closed contour to the path
+ * @param dir The direction to wind the rectangle's contour
+ */
+ public void addRect(RectF rect, Direction dir) {
+ if (rect == null) {
+ throw new NullPointerException("need rect parameter");
+ }
+ native_addRect(mNativePath, rect, dir.nativeInt);
+ }
+
+ /**
+ * Add a closed rectangle contour to the path
+ *
+ * @param left The left side of a rectangle to add to the path
+ * @param top The top of a rectangle to add to the path
+ * @param right The right side of a rectangle to add to the path
+ * @param bottom The bottom of a rectangle to add to the path
+ * @param dir The direction to wind the rectangle's contour
+ */
+ public void addRect(float left, float top, float right, float bottom,
+ Direction dir) {
+ native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt);
+ }
+
+ /**
+ * Add a closed oval contour to the path
+ *
+ * @param oval The bounds of the oval to add as a closed contour to the path
+ * @param dir The direction to wind the oval's contour
+ */
+ public void addOval(RectF oval, Direction dir) {
+ if (oval == null) {
+ throw new NullPointerException("need oval parameter");
+ }
+ native_addOval(mNativePath, oval, dir.nativeInt);
+ }
+
+ /**
+ * Add a closed circle contour to the path
+ *
+ * @param x The x-coordinate of the center of a circle to add to the path
+ * @param y The y-coordinate of the center of a circle to add to the path
+ * @param radius The radius of a circle to add to the path
+ * @param dir The direction to wind the circle's contour
+ */
+ public void addCircle(float x, float y, float radius, Direction dir) {
+ native_addCircle(mNativePath, x, y, radius, dir.nativeInt);
+ }
+
+ /**
+ * Add the specified arc to the path as a new contour.
+ *
+ * @param oval The bounds of oval defining the shape and size of the arc
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ */
+ public void addArc(RectF oval, float startAngle, float sweepAngle) {
+ if (oval == null) {
+ throw new NullPointerException("need oval parameter");
+ }
+ native_addArc(mNativePath, oval, startAngle, sweepAngle);
+ }
+
+ /**
+ * Add a closed round-rectangle contour to the path
+ *
+ * @param rect The bounds of a round-rectangle to add to the path
+ * @param rx The x-radius of the rounded corners on the round-rectangle
+ * @param ry The y-radius of the rounded corners on the round-rectangle
+ * @param dir The direction to wind the round-rectangle's contour
+ */
+ public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
+ if (rect == null) {
+ throw new NullPointerException("need rect parameter");
+ }
+ native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
+ }
+
+ /**
+ * Add a closed round-rectangle contour to the path. Each corner receives
+ * two radius values [X, Y]. The corners are ordered top-left, top-right,
+ * bottom-right, bottom-left
+ *
+ * @param rect The bounds of a round-rectangle to add to the path
+ * @param radii Array of 8 values, 4 pairs of [X,Y] radii
+ * @param dir The direction to wind the round-rectangle's contour
+ */
+ public void addRoundRect(RectF rect, float[] radii, Direction dir) {
+ if (rect == null) {
+ throw new NullPointerException("need rect parameter");
+ }
+ if (radii.length < 8) {
+ throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
+ }
+ native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
+ }
+
+ /**
+ * Add a copy of src to the path, offset by (dx,dy)
+ *
+ * @param src The path to add as a new contour
+ * @param dx The amount to translate the path in X as it is added
+ */
+ public void addPath(Path src, float dx, float dy) {
+ native_addPath(mNativePath, src.mNativePath, dx, dy);
+ }
+
+ /**
+ * Add a copy of src to the path
+ *
+ * @param src The path that is appended to the current path
+ */
+ public void addPath(Path src) {
+ native_addPath(mNativePath, src.mNativePath);
+ }
+
+ /**
+ * Add a copy of src to the path, transformed by matrix
+ *
+ * @param src The path to add as a new contour
+ */
+ public void addPath(Path src, Matrix matrix) {
+ native_addPath(mNativePath, src.mNativePath, matrix.native_instance);
+ }
+
+ /**
+ * Offset the path by (dx,dy), returning true on success
+ *
+ * @param dx The amount in the X direction to offset the entire path
+ * @param dy The amount in the Y direction to offset the entire path
+ * @param dst The translated path is written here. If this is null, then
+ * the original path is modified.
+ */
+ public void offset(float dx, float dy, Path dst) {
+ int dstNative = 0;
+ if (dst != null) {
+ dstNative = dst.mNativePath;
+ }
+ native_offset(mNativePath, dx, dy, dstNative);
+ }
+
+ /**
+ * Offset the path by (dx,dy), returning true on success
+ *
+ * @param dx The amount in the X direction to offset the entire path
+ * @param dy The amount in the Y direction to offset the entire path
+ */
+ public void offset(float dx, float dy) {
+ native_offset(mNativePath, dx, dy);
+ }
+
+ /**
+ * Sets the last point of the path.
+ *
+ * @param dx The new X coordinate for the last point
+ * @param dy The new Y coordinate for the last point
+ */
+ public void setLastPoint(float dx, float dy) {
+ native_setLastPoint(mNativePath, dx, dy);
+ }
+
+ /**
+ * Transform the points in this path by matrix, and write the answer
+ * into dst. If dst is null, then the the original path is modified.
+ *
+ * @param matrix The matrix to apply to the path
+ * @param dst The transformed path is written here. If dst is null,
+ * then the the original path is modified
+ */
+ public void transform(Matrix matrix, Path dst) {
+ int dstNative = 0;
+ if (dst != null) {
+ dstNative = dst.mNativePath;
+ }
+ native_transform(mNativePath, matrix.native_instance, dstNative);
+ }
+
+ /**
+ * Transform the points in this path by matrix.
+ *
+ * @param matrix The matrix to apply to the path
+ */
+ public void transform(Matrix matrix) {
+ native_transform(mNativePath, matrix.native_instance);
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ finalizer(mNativePath);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /*package*/ final int ni() {
+ return mNativePath;
+ }
+
+ private static native int init1();
+ private static native int init2(int nPath);
+ private static native void native_reset(int nPath);
+ private static native void native_rewind(int nPath);
+ private static native void native_set(int native_dst, int native_src);
+ private static native int native_getFillType(int nPath);
+ private static native void native_setFillType(int nPath, int ft);
+ private static native boolean native_isEmpty(int nPath);
+ private static native boolean native_isRect(int nPath, RectF rect);
+ private static native void native_computeBounds(int nPath, RectF bounds,
+ int btype);
+ private static native void native_incReserve(int nPath, int extraPtCount);
+ private static native void native_moveTo(int nPath, float x, float y);
+ private static native void native_rMoveTo(int nPath, float dx, float dy);
+ private static native void native_lineTo(int nPath, float x, float y);
+ private static native void native_rLineTo(int nPath, float dx, float dy);
+ private static native void native_quadTo(int nPath, float x1, float y1,
+ float x2, float y2);
+ private static native void native_rQuadTo(int nPath, float dx1, float dy1,
+ float dx2, float dy2);
+ private static native void native_cubicTo(int nPath, float x1, float y1,
+ float x2, float y2, float x3, float y3);
+ private static native void native_rCubicTo(int nPath, float x1, float y1,
+ float x2, float y2, float x3, float y3);
+ private static native void native_arcTo(int nPath, RectF oval,
+ float startAngle, float sweepAngle, boolean forceMoveTo);
+ private static native void native_close(int nPath);
+ private static native void native_addRect(int nPath, RectF rect, int dir);
+ private static native void native_addRect(int nPath, float left, float top,
+ float right, float bottom, int dir);
+ private static native void native_addOval(int nPath, RectF oval, int dir);
+ private static native void native_addCircle(int nPath, float x, float y,
+ float radius, int dir);
+ private static native void native_addArc(int nPath, RectF oval,
+ float startAngle, float sweepAngle);
+ private static native void native_addRoundRect(int nPath, RectF rect,
+ float rx, float ry, int dir);
+ private static native void native_addRoundRect(int nPath, RectF r,
+ float[] radii, int dir);
+ private static native void native_addPath(int nPath, int src, float dx,
+ float dy);
+ private static native void native_addPath(int nPath, int src);
+ private static native void native_addPath(int nPath, int src, int matrix);
+ private static native void native_offset(int nPath, float dx, float dy,
+ int dst_path);
+ private static native void native_offset(int nPath, float dx, float dy);
+ private static native void native_setLastPoint(int nPath, float dx, float dy);
+ private static native void native_transform(int nPath, int matrix,
+ int dst_path);
+ private static native void native_transform(int nPath, int matrix);
+ private static native void finalizer(int nPath);
+
+ private final int mNativePath;
+}
diff --git a/graphics/java/android/graphics/PathDashPathEffect.java b/graphics/java/android/graphics/PathDashPathEffect.java
new file mode 100644
index 0000000..e8ad5fd
--- /dev/null
+++ b/graphics/java/android/graphics/PathDashPathEffect.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class PathDashPathEffect extends PathEffect {
+
+ public enum Style {
+ TRANSLATE(0), //!< translate the shape to each position
+ ROTATE(1), //!< rotate the shape about its center
+ MORPH(2); //!< transform each point, and turn lines into curves
+
+ Style(int value) {
+ native_style = value;
+ }
+ int native_style;
+ }
+
+ /**
+ * Dash the drawn path by stamping it with the specified shape. This only
+ * applies to drawings when the paint's style is STROKE or STROKE_AND_FILL.
+ * If the paint's style is FILL, then this effect is ignored. The paint's
+ * strokeWidth does not affect the results.
+ * @param shape The path to stamp along
+ * @param advance spacing between each stamp of shape
+ * @param phase amount to offset before the first shape is stamped
+ * @param style how to transform the shape at each position as it is stamped
+ */
+ public PathDashPathEffect(Path shape, float advance, float phase,
+ Style style) {
+ native_instance = nativeCreate(shape.ni(), advance, phase,
+ style.native_style);
+ }
+
+ private static native int nativeCreate(int native_path, float advance,
+ float phase, int native_style);
+}
+
diff --git a/graphics/java/android/graphics/PathEffect.java b/graphics/java/android/graphics/PathEffect.java
new file mode 100644
index 0000000..9b2cd66
--- /dev/null
+++ b/graphics/java/android/graphics/PathEffect.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 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;
+
+/**
+ * PathEffect is the base class for objects in the Paint that affect
+ * the geometry of a drawing primitive before it is transformed by the
+ * canvas' matrix and drawn.
+ */
+public class PathEffect {
+
+ protected void finalize() throws Throwable {
+ nativeDestructor(native_instance);
+ }
+
+ private static native void nativeDestructor(int native_patheffect);
+ int native_instance;
+}
diff --git a/graphics/java/android/graphics/PathMeasure.java b/graphics/java/android/graphics/PathMeasure.java
new file mode 100644
index 0000000..98f7821
--- /dev/null
+++ b/graphics/java/android/graphics/PathMeasure.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class PathMeasure {
+
+ /**
+ * Create an empty PathMeasure object. To uses this to measure the length
+ * of a path, and/or to find the position and tangent along it, call
+ * setPath.
+ *
+ * Note that once a path is associated with the measure object, it is
+ * undefined if the path is subsequently modified and the the measure object
+ * is used. If the path is modified, you must call setPath with the path.
+ */
+ public PathMeasure() {
+ native_instance = native_create(0, false);
+ }
+
+ /**
+ * Create a PathMeasure object associated with the specified path object
+ * (already created and specified). The meansure object can now return the
+ * path's length, and the position and tangent of any position along the
+ * path.
+ *
+ * Note that once a path is associated with the measure object, it is
+ * undefined if the path is subsequently modified and the the measure object
+ * is used. If the path is modified, you must call setPath with the path.
+ *
+ * @param path The path that will be measured by this object
+ * @param forceClosed If true, then the path will be considered as "closed"
+ * even if its contour was not explicitly closed.
+ */
+ public PathMeasure(Path path, boolean forceClosed) {
+ // note: the native side makes a copy of path, so we don't need a java
+ // reference to it here, since it's fine if it gets GC'd
+ native_instance = native_create(path != null ? path.ni() : 0,
+ forceClosed);
+ }
+
+ /**
+ * Assign a new path, or null to have none.
+ */
+ public void setPath(Path path, boolean forceClosed) {
+ // note: the native side makes a copy of path, so we don't need a java
+ // reference to it here, since it's fine if it gets GC'd
+ native_setPath(native_instance,
+ path != null ? path.ni() : 0,
+ forceClosed);
+ }
+
+ /**
+ * Return the total length of the current contour, or 0 if no path is
+ * associated with this measure object.
+ */
+ public float getLength() {
+ return native_getLength(native_instance);
+ }
+
+ /**
+ * Pins distance to 0 <= distance <= getLength(), and then computes the
+ * corresponding position and tangent. Returns false if there is no path,
+ * or a zero-length path was specified, in which case position and tangent
+ * are unchanged.
+ *
+ * @param distance The distance along the current contour to sample
+ * @param pos If not null, eturns the sampled position (x==[0], y==[1])
+ * @param tan If not null, returns the sampled tangent (x==[0], y==[1])
+ * @return false if there was no path associated with this measure object
+ */
+ public boolean getPosTan(float distance, float pos[], float tan[]) {
+ if (pos != null && pos.length < 2 ||
+ tan != null && tan.length < 2) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return native_getPosTan(native_instance, distance, pos, tan);
+ }
+
+ public static final int POSITION_MATRIX_FLAG = 0x01; // must match flags in SkPathMeasure.h
+ public static final int TANGENT_MATRIX_FLAG = 0x02; // must match flags in SkPathMeasure.h
+
+ /**
+ * Pins distance to 0 <= distance <= getLength(), and then computes the
+ * corresponding matrix. Returns false if there is no path, or a zero-length
+ * path was specified, in which case matrix is unchanged.
+ *
+ * @param distance The distance along the associated path
+ * @param matrix Allocated by the caller, this is set to the transformation
+ * associated with the position and tangent at the specified distance
+ * @param flags Specified what aspects should be returned in the matrix.
+ */
+ public boolean getMatrix(float distance, Matrix matrix, int flags) {
+ return native_getMatrix(native_instance, distance, matrix.native_instance, flags);
+ }
+
+ /**
+ * Given a start and stop distance, return in dst the intervening
+ * segment(s). If the segment is zero-length, return false, else return
+ * true. startD and stopD are pinned to legal values (0..getLength()).
+ * If startD <= stopD then return false (and leave dst untouched).
+ * Begin the segment with a moveTo if startWithMoveTo is true
+ */
+ public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) {
+ return native_getSegment(native_instance, startD, stopD, dst.ni(), startWithMoveTo);
+ }
+
+ /**
+ * Return true if the current contour is closed()
+ */
+ public boolean isClosed() {
+ return native_isClosed(native_instance);
+ }
+
+ /**
+ * Move to the next contour in the path. Return true if one exists, or
+ * false if we're done with the path.
+ */
+ public boolean nextContour() {
+ return native_nextContour(native_instance);
+ }
+
+ protected void finalize() throws Throwable {
+ native_destroy(native_instance);
+ }
+
+ private static native int native_create(int native_path, boolean forceClosed);
+ private static native void native_setPath(int native_instance, int native_path, boolean forceClosed);
+ private static native float native_getLength(int native_instance);
+ private static native boolean native_getPosTan(int native_instance, float distance, float pos[], float tan[]);
+ private static native boolean native_getMatrix(int native_instance, float distance, int native_matrix, int flags);
+ private static native boolean native_getSegment(int native_instance, float startD, float stopD, int native_path, boolean startWithMoveTo);
+ private static native boolean native_isClosed(int native_instance);
+ private static native boolean native_nextContour(int native_instance);
+ private static native void native_destroy(int native_instance);
+
+ /* package */private final int native_instance;
+}
+
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
new file mode 100644
index 0000000..bbb2dbf
--- /dev/null
+++ b/graphics/java/android/graphics/Picture.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2007 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.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A picture records drawing calls (via the canvas returned by beginRecording)
+ * and can then play them back (via picture.draw(canvas) or canvas.drawPicture).
+ * The picture's contents can also be written to a stream, and then later
+ * restored to a new picture (via writeToStream / createFromStream). For most
+ * content (esp. text, lines, rectangles), drawing a sequence from a picture can
+ * be faster than the equivalent API calls, since the picture performs its
+ * playback without incurring any java-call overhead.
+ */
+public class Picture {
+ private Canvas mRecordingCanvas;
+ private final int mNativePicture;
+
+ private static final int WORKING_STREAM_STORAGE = 16 * 1024;
+
+ public Picture() {
+ this(nativeConstructor(0));
+ }
+
+ /**
+ * Create a picture by making a copy of what has already been recorded in
+ * src. The contents of src are unchanged, and if src changes later, those
+ * changes will not be reflected in this picture.
+ */
+ public Picture(Picture src) {
+ this(nativeConstructor(src != null ? src.mNativePicture : 0));
+ }
+
+ /**
+ * To record a picture, call beginRecording() and then draw into the Canvas
+ * that is returned. Nothing we appear on screen, but all of the draw
+ * commands (e.g. drawRect(...)) will be recorded. To stop recording, call
+ * endRecording(). At this point the Canvas that was returned must no longer
+ * be referenced, and nothing should be drawn into it.
+ */
+ public Canvas beginRecording(int width, int height) {
+ int ni = nativeBeginRecording(mNativePicture, width, height);
+ mRecordingCanvas = new RecordingCanvas(this, ni);
+ return mRecordingCanvas;
+ }
+
+ /**
+ * Call endRecording when the picture is built. After this call, the picture
+ * may be drawn, but the canvas that was returned by beginRecording must not
+ * be referenced anymore. This is automatically called if Picture.draw() or
+ * Canvas.drawPicture() is called.
+ */
+ public void endRecording() {
+ if (mRecordingCanvas != null) {
+ mRecordingCanvas = null;
+ nativeEndRecording(mNativePicture);
+ }
+ }
+
+ /**
+ * Get the width of the picture as passed to beginRecording. This
+ * does not reflect (per se) the content of the picture.
+ */
+ public native int getWidth();
+
+ /**
+ * Get the height of the picture as passed to beginRecording. This
+ * does not reflect (per se) the content of the picture.
+ */
+ public native int getHeight();
+
+ /**
+ * Draw this picture on the canvas. The picture may have the side effect
+ * of changing the matrix and clip of the canvas.
+ *
+ * @param canvas The picture is drawn to this canvas
+ */
+ public void draw(Canvas canvas) {
+ if (mRecordingCanvas != null) {
+ endRecording();
+ }
+ nativeDraw(canvas.mNativeCanvas, mNativePicture);
+ }
+
+ /**
+ * Create a new picture (already recorded) from the data in the stream. This
+ * data was generated by a previous call to writeToStream().
+ */
+ public static Picture createFromStream(InputStream stream) {
+ return new Picture(
+ nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]));
+ }
+
+ /**
+ * Write the picture contents to a stream. The data can be used to recreate
+ * the picture in this or another process by calling createFromStream.
+ */
+ public void writeToStream(OutputStream stream) {
+ // do explicit check before calling the native method
+ if (stream == null) {
+ throw new NullPointerException();
+ }
+ if (!nativeWriteToStream(mNativePicture, stream,
+ new byte[WORKING_STREAM_STORAGE])) {
+ throw new RuntimeException();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ nativeDestructor(mNativePicture);
+ }
+
+ /*package*/ final int ni() {
+ return mNativePicture;
+ }
+
+ private Picture(int nativePicture) {
+ if (nativePicture == 0) {
+ throw new RuntimeException();
+ }
+ mNativePicture = nativePicture;
+ }
+
+ // return empty picture if src is 0, or a copy of the native src
+ private static native int nativeConstructor(int nativeSrcOr0);
+ private static native int nativeCreateFromStream(InputStream stream,
+ byte[] storage);
+ private static native int nativeBeginRecording(int nativeCanvas,
+ int w, int h);
+ private static native void nativeEndRecording(int nativeCanvas);
+ private static native void nativeDraw(int nativeCanvas, int nativePicture);
+ private static native boolean nativeWriteToStream(int nativePicture,
+ OutputStream stream, byte[] storage);
+ private static native void nativeDestructor(int nativePicture);
+
+ private static class RecordingCanvas extends Canvas {
+ private final Picture mPicture;
+
+ public RecordingCanvas(Picture pict, int nativeCanvas) {
+ super(nativeCanvas);
+ mPicture = pict;
+ }
+
+ @Override
+ public void setBitmap(Bitmap bitmap) {
+ throw new RuntimeException(
+ "Cannot call setBitmap on a picture canvas");
+ }
+
+ @Override
+ public void drawPicture(Picture picture) {
+ if (mPicture == picture) {
+ throw new RuntimeException(
+ "Cannot draw a picture into its recording canvas");
+ }
+ super.drawPicture(picture);
+ }
+ }
+}
+
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
new file mode 100644
index 0000000..159accc
--- /dev/null
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class PixelFormat
+{
+ /* these constants need to match those
+ in ui/PixelFormat.h & pixelflinger/format.h */
+
+ public static final int UNKNOWN = 0;
+
+ /** System chooses a format that supports translucency (many alpha bits) */
+ public static final int TRANSLUCENT = -3;
+
+ /**
+ * System chooses a format that supports transparency
+ * (at least 1 alpha bit)
+ */
+ public static final int TRANSPARENT = -2;
+
+ /** System chooses an opaque format (no alpha bits required) */
+ public static final int OPAQUE = -1;
+
+ public static final int RGBA_8888 = 1;
+ public static final int RGBX_8888 = 2;
+ public static final int RGB_888 = 3;
+ public static final int RGB_565 = 4;
+
+ public static final int RGBA_5551 = 6;
+ public static final int RGBA_4444 = 7;
+ public static final int A_8 = 8;
+ public static final int L_8 = 9;
+ public static final int LA_88 = 0xA;
+ public static final int RGB_332 = 0xB;
+
+ /**
+ * YCbCr formats, used for video. These are not necessarily supported
+ * by the hardware.
+ */
+ public static final int YCbCr_422_SP= 0x10;
+ public static final int YCbCr_420_SP= 0x11;
+
+ /**
+ * Encoded formats. These are not necessarily supported by the hardware.
+ */
+ public static final int JPEG = 0x100;
+
+ /*
+ * We use a class initializer to allow the native code to cache some
+ * field offsets.
+ */
+ native private static void nativeClassInit();
+ static { nativeClassInit(); }
+
+ public static native void getPixelFormatInfo(int format, PixelFormat info);
+ public static boolean formatHasAlpha(int format) {
+ switch (format) {
+ case PixelFormat.A_8:
+ case PixelFormat.LA_88:
+ case PixelFormat.RGBA_4444:
+ case PixelFormat.RGBA_5551:
+ case PixelFormat.RGBA_8888:
+ case PixelFormat.TRANSLUCENT:
+ case PixelFormat.TRANSPARENT:
+ return true;
+ }
+ return false;
+ }
+
+ public int bytesPerPixel;
+ public int bitsPerPixel;
+}
diff --git a/graphics/java/android/graphics/PixelXorXfermode.java b/graphics/java/android/graphics/PixelXorXfermode.java
new file mode 100644
index 0000000..18d15cf
--- /dev/null
+++ b/graphics/java/android/graphics/PixelXorXfermode.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 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;
+
+/**
+ * PixelXorXfermode implements a simple pixel xor (op ^ src ^ dst).
+ * This transformation does not follow premultiplied conventions, therefore
+ * this mode *always* returns an opaque color (alpha == 255). Thus it is
+ * not really usefull for operating on blended colors.
+ */
+public class PixelXorXfermode extends Xfermode {
+
+ public PixelXorXfermode(int opColor) {
+ native_instance = nativeCreate(opColor);
+ }
+
+ private static native int nativeCreate(int opColor);
+}
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
new file mode 100644
index 0000000..c351444
--- /dev/null
+++ b/graphics/java/android/graphics/Point.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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;
+
+
+/**
+ * Point holds two integer coordinates
+ */
+public class Point {
+ public int x;
+ public int y;
+
+ public Point() {}
+
+ public Point(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Point(Point src) {
+ this.x = src.x;
+ this.y = src.y;
+ }
+
+ /**
+ * Set the point's x and y coordinates
+ */
+ public void set(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Negate the point's coordinates
+ */
+ public final void negate() {
+ x = -x;
+ y = -y;
+ }
+
+ /**
+ * Offset the point's coordinates by dx, dy
+ */
+ public final void offset(int dx, int dy) {
+ x += dx;
+ y += dy;
+ }
+
+ /**
+ * Returns true if the point's coordinates equal (x,y)
+ */
+ public final boolean equals(int x, int y) {
+ return this.x == x && this.y == y;
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o instanceof Point) {
+ Point p = (Point) o;
+ return this.x == p.x && this.y == p.y;
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return x * 32713 + y;
+ }
+
+ @Override public String toString() {
+ return "Point(" + x + ", " + y+ ")";
+ }
+}
diff --git a/graphics/java/android/graphics/PointF.java b/graphics/java/android/graphics/PointF.java
new file mode 100644
index 0000000..0f045a1
--- /dev/null
+++ b/graphics/java/android/graphics/PointF.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 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 android.util.FloatMath;
+
+
+/**
+ * PointF holds two float coordinates
+ */
+public class PointF {
+ public float x;
+ public float y;
+
+ public PointF() {}
+
+ public PointF(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public PointF(Point p) {
+ this.x = p.x;
+ this.y = p.y;
+ }
+
+ /**
+ * Set the point's x and y coordinates
+ */
+ public final void set(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Set the point's x and y coordinates to the coordinates of p
+ */
+ public final void set(PointF p) {
+ this.x = p.x;
+ this.y = p.y;
+ }
+
+ public final void negate() {
+ x = -x;
+ y = -y;
+ }
+
+ public final void offset(float dx, float dy) {
+ x += dx;
+ y += dy;
+ }
+
+ /**
+ * Returns true if the point's coordinates equal (x,y)
+ */
+ public final boolean equals(float x, float y) {
+ return this.x == x && this.y == y;
+ }
+
+ /**
+ * Return the euclidian distance from (0,0) to the point
+ */
+ public final float length() {
+ return length(x, y);
+ }
+
+ /**
+ * Returns the euclidian distance from (0,0) to (x,y)
+ */
+ public static float length(float x, float y) {
+ return FloatMath.sqrt(x * x + y * y);
+ }
+}
+
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
new file mode 100644
index 0000000..3904234
--- /dev/null
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class PorterDuff {
+
+ // these value must match their native equivalents. See SkPorterDuff.h
+ public enum Mode {
+ /** [0, 0] */
+ CLEAR (0),
+ /** [Sa, Sc] */
+ SRC (1),
+ /** [Da, Dc] */
+ DST (2),
+ /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
+ SRC_OVER (3),
+ /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
+ DST_OVER (4),
+ /** [Sa * Da, Sc * Da] */
+ SRC_IN (5),
+ /** [Sa * Da, Sa * Dc] */
+ DST_IN (6),
+ /** [Sa * (1 - Da), Sc * (1 - Da)] */
+ SRC_OUT (7),
+ /** [Da * (1 - Sa), Dc * (1 - Sa)] */
+ DST_OUT (8),
+ /** [Da, Sc * Da + (1 - Sa) * Dc] */
+ SRC_ATOP (9),
+ /** [Sa, Sa * Dc + Sc * (1 - Da)] */
+ DST_ATOP (10),
+ /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
+ XOR (11),
+ /** [Sa + Da - Sa*Da,
+ Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
+ DARKEN (12),
+ /** [Sa + Da - Sa*Da,
+ Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
+ LIGHTEN (13),
+ /** [Sa * Da, Sc * Dc] */
+ MULTIPLY (14),
+ /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
+ SCREEN (15);
+
+ Mode(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+}
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
new file mode 100644
index 0000000..06724bd
--- /dev/null
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class PorterDuffColorFilter extends ColorFilter {
+ /**
+ * Create a colorfilter that uses the specified color and porter-duff mode.
+ *
+ * @param srcColor The source color used with the specified
+ * porter-duff mode
+ * @param mode The porter-duff mode that is applied
+ */
+ public PorterDuffColorFilter(int srcColor, PorterDuff.Mode mode) {
+ native_instance = native_CreatePorterDuffFilter(srcColor,
+ mode.nativeInt);
+ }
+
+ private static native int native_CreatePorterDuffFilter(int srcColor,
+ int porterDuffMode);
+}
diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java
new file mode 100644
index 0000000..cb127fd
--- /dev/null
+++ b/graphics/java/android/graphics/PorterDuffXfermode.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class PorterDuffXfermode extends Xfermode {
+ /**
+ * Create an xfermode that uses the specified porter-duff mode.
+ *
+ * @param mode The porter-duff mode that is applied
+ */
+ public PorterDuffXfermode(PorterDuff.Mode mode) {
+ native_instance = nativeCreateXfermode(mode.nativeInt);
+ }
+
+ private static native int nativeCreateXfermode(int mode);
+}
diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java
new file mode 100644
index 0000000..b4e902d
--- /dev/null
+++ b/graphics/java/android/graphics/RadialGradient.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class RadialGradient extends Shader {
+
+ /** Create a shader that draws a radial gradient given the center and radius.
+ @param x The x-coordinate of the center of the radius
+ @param y The y-coordinate of the center of the radius
+ @param radius Must be positive. The radius of the circle for this gradient
+ @param colors The colors to be distributed between the center and edge of the circle
+ @param positions May be NULL. The relative position of
+ each corresponding color in the colors array. If this is NULL,
+ the the colors are distributed evenly between the center and edge of the circle.
+ @param tile The Shader tiling mode
+ */
+ public RadialGradient(float x, float y, float radius,
+ int colors[], float positions[], TileMode tile) {
+ if (radius <= 0) {
+ throw new IllegalArgumentException("radius must be > 0");
+ }
+ if (colors.length < 2) {
+ throw new IllegalArgumentException("needs >= 2 number of colors");
+ }
+ if (positions != null && colors.length != positions.length) {
+ throw new IllegalArgumentException("color and position arrays must be of equal length");
+ }
+ native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
+ }
+
+ /** Create a shader that draws a radial gradient given the center and radius.
+ @param x The x-coordinate of the center of the radius
+ @param y The y-coordinate of the center of the radius
+ @param radius Must be positive. The radius of the circle for this gradient
+ @param color0 The color at the center of the circle.
+ @param color1 The color at the edge of the circle.
+ @param tile The Shader tiling mode
+ */
+ public RadialGradient(float x, float y, float radius,
+ int color0, int color1, TileMode tile) {
+ if (radius <= 0) {
+ throw new IllegalArgumentException("radius must be > 0");
+ }
+ native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
+ }
+
+ private static native int nativeCreate1(float x, float y, float radius,
+ int colors[], float positions[], int tileMode);
+ private static native int nativeCreate2(float x, float y, float radius,
+ int color0, int color1, int tileMode);
+}
+
diff --git a/graphics/java/android/graphics/Rasterizer.java b/graphics/java/android/graphics/Rasterizer.java
new file mode 100644
index 0000000..feb5f0c
--- /dev/null
+++ b/graphics/java/android/graphics/Rasterizer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+// This file was generated from the C++ include file: SkRasterizer.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+package android.graphics;
+
+public class Rasterizer {
+
+ protected void finalize() throws Throwable {
+ finalizer(native_instance);
+ }
+
+ private static native void finalizer(int native_instance);
+
+ int native_instance;
+}
diff --git a/graphics/java/android/graphics/Rect.aidl b/graphics/java/android/graphics/Rect.aidl
new file mode 100644
index 0000000..09edbfe
--- /dev/null
+++ b/graphics/java/android/graphics/Rect.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/graphics/Rect.aidl
+**
+** Copyright 2007, 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;
+
+parcelable Rect;
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
new file mode 100644
index 0000000..d8d7136
--- /dev/null
+++ b/graphics/java/android/graphics/Rect.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2006 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 android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Rect holds four integer coordinates for a rectangle. The rectangle is
+ * represented by the coordinates of its 4 edges (left, top, right bottom).
+ * These fields can be accessed directly. Use width() and height() to retrieve
+ * the rectangle's width and height. Note: most methods do not check to see that
+ * the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
+ */
+public final class Rect implements Parcelable {
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+
+ /**
+ * Create a new empty Rect. All coordinates are initialized to 0.
+ */
+ public Rect() {}
+
+ /**
+ * Create a new rectangle with the specified coordinates. Note: no range
+ * checking is performed, so the caller must ensure that left <= right and
+ * top <= bottom.
+ *
+ * @param left The X coordinate of the left side of the rectagle
+ * @param top The Y coordinate of the top of the rectangle
+ * @param right The X coordinate of the right side of the rectagle
+ * @param bottom The Y coordinate of the bottom of the rectangle
+ */
+ public Rect(int left, int top, int right, int bottom) {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ /**
+ * Create a new rectangle, initialized with the values in the specified
+ * rectangle (which is left unmodified).
+ *
+ * @param r The rectangle whose coordinates are copied into the new
+ * rectangle.
+ */
+ public Rect(Rect r) {
+ left = r.left;
+ top = r.top;
+ right = r.right;
+ bottom = r.bottom;
+ }
+
+ public boolean equals(Object obj) {
+ Rect r = (Rect) obj;
+ if (r != null) {
+ return left == r.left && top == r.top && right == r.right
+ && bottom == r.bottom;
+ }
+ return false;
+ }
+
+ public String toString() {
+ return "Rect(" + left + ", " + top + ", " + right + ", " + bottom + ")";
+ }
+
+ /**
+ * Returns true if the rectangle is empty (left >= right or top >= bottom)
+ */
+ public final boolean isEmpty() {
+ return left >= right || top >= bottom;
+ }
+
+ /**
+ * @return the rectangle's width. This does not check for a valid rectangle
+ * (i.e. left <= right) so the result may be negative.
+ */
+ public final int width() {
+ return right - left;
+ }
+
+ /**
+ * @return the rectangle's height. This does not check for a valid rectangle
+ * (i.e. top <= bottom) so the result may be negative.
+ */
+ public final int height() {
+ return bottom - top;
+ }
+
+ /**
+ * @return the horizontal center of the rectangle. If the computed value
+ * is fractional, this method returns the largest integer that is
+ * less than the computed value.
+ */
+ public final int centerX() {
+ return (left + right) >> 1;
+ }
+
+ /**
+ * @return the vertical center of the rectangle. If the computed value
+ * is fractional, this method returns the largest integer that is
+ * less than the computed value.
+ */
+ public final int centerY() {
+ return (top + bottom) >> 1;
+ }
+
+ /**
+ * @return the exact horizontal center of the rectangle as a float.
+ */
+ public final float exactCenterX() {
+ return (left + right) * 0.5f;
+ }
+
+ /**
+ * @return the exact vertical center of the rectangle as a float.
+ */
+ public final float exactCenterY() {
+ return (top + bottom) * 0.5f;
+ }
+
+ /**
+ * Set the rectangle to (0,0,0,0)
+ */
+ public void setEmpty() {
+ left = right = top = bottom = 0;
+ }
+
+ /**
+ * Set the rectangle's coordinates to the specified values. Note: no range
+ * checking is performed, so it is up to the caller to ensure that
+ * left <= right and top <= bottom.
+ *
+ * @param left The X coordinate of the left side of the rectagle
+ * @param top The Y coordinate of the top of the rectangle
+ * @param right The X coordinate of the right side of the rectagle
+ * @param bottom The Y coordinate of the bottom of the rectangle
+ */
+ public void set(int left, int top, int right, int bottom) {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ /**
+ * Copy the coordinates from src into this rectangle.
+ *
+ * @param src The rectangle whose coordinates are copied into this
+ * rectangle.
+ */
+ public void set(Rect src) {
+ this.left = src.left;
+ this.top = src.top;
+ this.right = src.right;
+ this.bottom = src.bottom;
+ }
+
+ /**
+ * Offset the rectangle by adding dx to its left and right coordinates, and
+ * adding dy to its top and bottom coordinates.
+ *
+ * @param dx The amount to add to the rectangle's left and right coordinates
+ * @param dy The amount to add to the rectangle's top and bottom coordinates
+ */
+ public void offset(int dx, int dy) {
+ left += dx;
+ top += dy;
+ right += dx;
+ bottom += dy;
+ }
+
+ /**
+ * Offset the rectangle to a specific (left, top) position,
+ * keeping its width and height the same.
+ *
+ * @param newLeft The new "left" coordinate for the rectangle
+ * @param newTop The new "top" coordinate for the rectangle
+ */
+ public void offsetTo(int newLeft, int newTop) {
+ right += newLeft - left;
+ bottom += newTop - top;
+ left = newLeft;
+ top = newTop;
+ }
+
+ /**
+ * Inset the rectangle by (dx,dy). If dx is positive, then the sides are
+ * moved inwards, making the rectangle narrower. If dx is negative, then the
+ * sides are moved outwards, making the rectangle wider. The same holds true
+ * for dy and the top and bottom.
+ *
+ * @param dx The amount to add(subtract) from the rectangle's left(right)
+ * @param dy The amount to add(subtract) from the rectangle's top(bottom)
+ */
+ public void inset(int dx, int dy) {
+ left += dx;
+ top += dy;
+ right -= dx;
+ bottom -= dy;
+ }
+
+ /**
+ * Returns true if (x,y) is inside the rectangle. The left and top are
+ * considered to be inside, while the right and bottom are not. This means
+ * that for a x,y to be contained: left <= x < right and top <= y < bottom.
+ * An empty rectangle never contains any point.
+ *
+ * @param x The X coordinate of the point being tested for containment
+ * @param y The Y coordinate of the point being tested for containment
+ * @return true iff (x,y) are contained by the rectangle, where containment
+ * means left <= x < right and top <= y < bottom
+ */
+ public boolean contains(int x, int y) {
+ return left < right && top < bottom // check for empty first
+ && x >= left && x < right && y >= top && y < bottom;
+ }
+
+ /**
+ * Returns true iff the 4 specified sides of a rectangle are inside or equal
+ * to this rectangle. i.e. is this rectangle a superset of the specified
+ * rectangle. An empty rectangle never contains another rectangle.
+ *
+ * @param left The left side of the rectangle being tested for containment
+ * @param top The top of the rectangle being tested for containment
+ * @param right The right side of the rectangle being tested for containment
+ * @param bottom The bottom of the rectangle being tested for containment
+ * @return true iff the the 4 specified sides of a rectangle are inside or
+ * equal to this rectangle
+ */
+ public boolean contains(int left, int top, int right, int bottom) {
+ // check for empty first
+ return this.left < this.right && this.top < this.bottom
+ // now check for containment
+ && this.left <= left && this.top <= top
+ && this.right >= right && this.bottom >= bottom;
+ }
+
+ /**
+ * Returns true iff the specified rectangle r is inside or equal to this
+ * rectangle. An empty rectangle never contains another rectangle.
+ *
+ * @param r The rectangle being tested for containment.
+ * @return true iff the specified rectangle r is inside or equal to this
+ * rectangle
+ */
+ public boolean contains(Rect r) {
+ // check for empty first
+ return this.left < this.right && this.top < this.bottom
+ // now check for containment
+ && left <= r.left && top <= r.top
+ && right >= r.right && bottom >= r.bottom;
+ }
+
+ /**
+ * If the rectangle specified by left,top,right,bottom intersects this
+ * rectangle, return true and set this rectangle to that intersection,
+ * otherwise return false and do not change this rectangle. No check is
+ * performed to see if either rectangle is empty. Note: To just test for
+ * intersection, use intersects()
+ *
+ * @param left The left side of the rectangle being intersected with this
+ * rectangle
+ * @param top The top of the rectangle being intersected with this rectangle
+ * @param right The right side of the rectangle being intersected with this
+ * rectangle.
+ * @param bottom The bottom of the rectangle being intersected with this
+ * rectangle.
+ * @return true if the specified rectangle and this rectangle intersect
+ * (and this rectangle is then set to that intersection) else
+ * return false and do not change this rectangle.
+ */
+ public boolean intersect(int left, int top, int right, int bottom) {
+ if (this.left < right && left < this.right
+ && this.top < bottom && top < this.bottom) {
+ if (this.left < left) {
+ this.left = left;
+ }
+ if (this.top < top) {
+ this.top = top;
+ }
+ if (this.right > right) {
+ this.right = right;
+ }
+ if (this.bottom > bottom) {
+ this.bottom = bottom;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * If the specified rectangle intersects this rectangle, return true and set
+ * this rectangle to that intersection, otherwise return false and do not
+ * change this rectangle. No check is performed to see if either rectangle
+ * is empty. To just test for intersection, use intersects()
+ *
+ * @param r The rectangle being intersected with this rectangle.
+ * @return true if the specified rectangle and this rectangle intersect
+ * (and this rectangle is then set to that intersection) else
+ * return false and do not change this rectangle.
+ */
+ public boolean intersect(Rect r) {
+ return intersect(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * If rectangles a and b intersect, return true and set this rectangle to
+ * that intersection, otherwise return false and do not change this
+ * rectangle. No check is performed to see if either rectangle is empty.
+ * To just test for intersection, use intersects()
+ *
+ * @param a The first rectangle being intersected with
+ * @param b The second rectangle being intersected with
+ * @return true iff the two specified rectangles intersect. If they do, set
+ * this rectangle to that intersection. If they do not, return
+ * false and do not change this rectangle.
+ */
+ public boolean setIntersect(Rect a, Rect b) {
+ if (a.left < b.right && b.left < a.right
+ && a.top < b.bottom && b.top < a.bottom) {
+ left = Math.max(a.left, b.left);
+ top = Math.max(a.top, b.top);
+ right = Math.min(a.right, b.right);
+ bottom = Math.min(a.bottom, b.bottom);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this rectangle intersects the specified rectangle.
+ * In no event is this rectangle modified. No check is performed to see
+ * if either rectangle is empty. To record the intersection, use intersect()
+ * or setIntersect().
+ *
+ * @param left The left side of the rectangle being tested for intersection
+ * @param top The top of the rectangle being tested for intersection
+ * @param right The right side of the rectangle being tested for
+ * intersection
+ * @param bottom The bottom of the rectangle being tested for intersection
+ * @return true iff the specified rectangle intersects this rectangle. In
+ * no event is this rectangle modified.
+ */
+ public boolean intersects(int left, int top, int right, int bottom) {
+ return this.left < right && left < this.right
+ && this.top < bottom && top < this.bottom;
+ }
+
+ /**
+ * Returns true iff the two specified rectangles intersect. In no event are
+ * either of the rectangles modified. To record the intersection,
+ * use intersect() or setIntersect().
+ *
+ * @param a The first rectangle being tested for intersection
+ * @param b The second rectangle being tested for intersection
+ * @return true iff the two specified rectangles intersect. In no event are
+ * either of the rectangles modified.
+ */
+ public static boolean intersects(Rect a, Rect b) {
+ return a.left < b.right && b.left < a.right
+ && a.top < b.bottom && b.top < a.bottom;
+ }
+
+ /**
+ * Update this Rect to enclose itself and the specified rectangle. If the
+ * specified rectangle is empty, nothing is done. If this rectangle is empty
+ * it is set to the specified rectangle.
+ *
+ * @param left The left edge being unioned with this rectangle
+ * @param top The top edge being unioned with this rectangle
+ * @param right The right edge being unioned with this rectangle
+ * @param bottom The bottom edge being unioned with this rectangle
+ */
+ public void union(int left, int top, int right, int bottom) {
+ if ((left < right) && (top < bottom)) {
+ if ((this.left < this.right) && (this.top < this.bottom)) {
+ if (this.left > left)
+ this.left = left;
+ if (this.top > top)
+ this.top = top;
+ if (this.right < right)
+ this.right = right;
+ if (this.bottom < bottom)
+ this.bottom = bottom;
+ } else {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+ }
+ }
+
+ /**
+ * Update this Rect to enclose itself and the specified rectangle. If the
+ * specified rectangle is empty, nothing is done. If this rectangle is empty
+ * it is set to the specified rectangle.
+ *
+ * @param r The rectangle being unioned with this rectangle
+ */
+ public void union(Rect r) {
+ union(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Update this Rect to enclose itself and the [x,y] coordinate. There is no
+ * check to see that this rectangle is non-empty.
+ *
+ * @param x The x coordinate of the point to add to the rectangle
+ * @param y The y coordinate of the point to add to the rectangle
+ */
+ public void union(int x, int y) {
+ if (x < left) {
+ left = x;
+ } else if (x > right) {
+ right = x;
+ }
+ if (y < top) {
+ top = y;
+ } else if (y > bottom) {
+ bottom = y;
+ }
+ }
+
+ /**
+ * Swap top/bottom or left/right if there are flipped (i.e. left > right
+ * and/or top > bottom). This can be called if
+ * the edges are computed separately, and may have crossed over each other.
+ * If the edges are already correct (i.e. left <= right and top <= bottom)
+ * then nothing is done.
+ */
+ public void sort() {
+ if (left > right) {
+ int temp = left;
+ left = right;
+ right = temp;
+ }
+ if (top > bottom) {
+ int temp = top;
+ top = bottom;
+ bottom = temp;
+ }
+ }
+
+ /**
+ * Parcelable interface methods
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write this rectangle to the specified parcel. To restore a rectangle from
+ * a parcel, use readFromParcel()
+ * @param out The parcel to write the rectangle's coordinates into
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(left);
+ out.writeInt(top);
+ out.writeInt(right);
+ out.writeInt(bottom);
+ }
+
+ public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {
+ /**
+ * Return a new rectangle from the data in the specified parcel.
+ */
+ public Rect createFromParcel(Parcel in) {
+ Rect r = new Rect();
+ r.readFromParcel(in);
+ return r;
+ }
+
+ /**
+ * Return an array of rectangles of the specified size.
+ */
+ public Rect[] newArray(int size) {
+ return new Rect[size];
+ }
+ };
+
+ /**
+ * Set the rectangle's coordinates from the data stored in the specified
+ * parcel. To write a rectangle to a parcel, call writeToParcel().
+ *
+ * @param in The parcel to read the rectangle's coordinates from
+ */
+ public void readFromParcel(Parcel in) {
+ left = in.readInt();
+ top = in.readInt();
+ right = in.readInt();
+ bottom = in.readInt();
+ }
+}
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
new file mode 100644
index 0000000..d71f2dc
--- /dev/null
+++ b/graphics/java/android/graphics/RectF.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2006 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 android.util.FloatMath;
+import com.android.internal.util.FastMath;
+
+/**
+ * RectF holds four float coordinates for a rectangle. The rectangle is
+ * represented by the coordinates of its 4 edges (left, top, right bottom).
+ * These fields can be accessed directly. Use width() and height() to retrieve
+ * the rectangle's width and height. Note: most methods do not check to see that
+ * the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
+ */
+public class RectF {
+ public float left;
+ public float top;
+ public float right;
+ public float bottom;
+
+ /**
+ * Create a new empty RectF. All coordinates are initialized to 0.
+ */
+ public RectF() {}
+
+ /**
+ * Create a new rectangle with the specified coordinates. Note: no range
+ * checking is performed, so the caller must ensure that left <= right and
+ * top <= bottom.
+ *
+ * @param left The X coordinate of the left side of the rectagle
+ * @param top The Y coordinate of the top of the rectangle
+ * @param right The X coordinate of the right side of the rectagle
+ * @param bottom The Y coordinate of the bottom of the rectangle
+ */
+ public RectF(float left, float top, float right, float bottom) {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ /**
+ * Create a new rectangle, initialized with the values in the specified
+ * rectangle (which is left unmodified).
+ *
+ * @param r The rectangle whose coordinates are copied into the new
+ * rectangle.
+ */
+ public RectF(RectF r) {
+ left = r.left;
+ top = r.top;
+ right = r.right;
+ bottom = r.bottom;
+ }
+
+ public RectF(Rect r) {
+ left = r.left;
+ top = r.top;
+ right = r.right;
+ bottom = r.bottom;
+ }
+
+ public String toString() {
+ return "RectF(" + left + ", " + top + ", "
+ + right + ", " + bottom + ")";
+ }
+
+ /**
+ * Returns true if the rectangle is empty (left >= right or top >= bottom)
+ */
+ public final boolean isEmpty() {
+ return left >= right || top >= bottom;
+ }
+
+ /**
+ * @return the rectangle's width. This does not check for a valid rectangle
+ * (i.e. left <= right) so the result may be negative.
+ */
+ public final float width() {
+ return right - left;
+ }
+
+ /**
+ * @return the rectangle's height. This does not check for a valid rectangle
+ * (i.e. top <= bottom) so the result may be negative.
+ */
+ public final float height() {
+ return bottom - top;
+ }
+
+ /**
+ * @return the horizontal center of the rectangle. This does not check for
+ * a valid rectangle (i.e. left <= right)
+ */
+ public final float centerX() {
+ return (left + right) * 0.5f;
+ }
+
+ /**
+ * @return the vertical center of the rectangle. This does not check for
+ * a valid rectangle (i.e. top <= bottom)
+ */
+ public final float centerY() {
+ return (top + bottom) * 0.5f;
+ }
+
+ /**
+ * Set the rectangle to (0,0,0,0)
+ */
+ public void setEmpty() {
+ left = right = top = bottom = 0;
+ }
+
+ /**
+ * Set the rectangle's coordinates to the specified values. Note: no range
+ * checking is performed, so it is up to the caller to ensure that
+ * left <= right and top <= bottom.
+ *
+ * @param left The X coordinate of the left side of the rectagle
+ * @param top The Y coordinate of the top of the rectangle
+ * @param right The X coordinate of the right side of the rectagle
+ * @param bottom The Y coordinate of the bottom of the rectangle
+ */
+ public void set(float left, float top, float right, float bottom) {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ /**
+ * Copy the coordinates from src into this rectangle.
+ *
+ * @param src The rectangle whose coordinates are copied into this
+ * rectangle.
+ */
+ public void set(RectF src) {
+ this.left = src.left;
+ this.top = src.top;
+ this.right = src.right;
+ this.bottom = src.bottom;
+ }
+
+ /**
+ * Copy the coordinates from src into this rectangle.
+ *
+ * @param src The rectangle whose coordinates are copied into this
+ * rectangle.
+ */
+ public void set(Rect src) {
+ this.left = src.left;
+ this.top = src.top;
+ this.right = src.right;
+ this.bottom = src.bottom;
+ }
+
+ /**
+ * Offset the rectangle by adding dx to its left and right coordinates, and
+ * adding dy to its top and bottom coordinates.
+ *
+ * @param dx The amount to add to the rectangle's left and right coordinates
+ * @param dy The amount to add to the rectangle's top and bottom coordinates
+ */
+ public void offset(float dx, float dy) {
+ left += dx;
+ top += dy;
+ right += dx;
+ bottom += dy;
+ }
+
+ /**
+ * Offset the rectangle to a specific (left, top) position,
+ * keeping its width and height the same.
+ *
+ * @param newLeft The new "left" coordinate for the rectangle
+ * @param newTop The new "top" coordinate for the rectangle
+ */
+ public void offsetTo(float newLeft, float newTop) {
+ right += newLeft - left;
+ bottom += newTop - top;
+ left = newLeft;
+ top = newTop;
+ }
+
+ /**
+ * Inset the rectangle by (dx,dy). If dx is positive, then the sides are
+ * moved inwards, making the rectangle narrower. If dx is negative, then the
+ * sides are moved outwards, making the rectangle wider. The same holds true
+ * for dy and the top and bottom.
+ *
+ * @param dx The amount to add(subtract) from the rectangle's left(right)
+ * @param dy The amount to add(subtract) from the rectangle's top(bottom)
+ */
+ public void inset(float dx, float dy) {
+ left += dx;
+ top += dy;
+ right -= dx;
+ bottom -= dy;
+ }
+
+ /**
+ * Returns true if (x,y) is inside the rectangle. The left and top are
+ * considered to be inside, while the right and bottom are not. This means
+ * that for a x,y to be contained: left <= x < right and top <= y < bottom.
+ * An empty rectangle never contains any point.
+ *
+ * @param x The X coordinate of the point being tested for containment
+ * @param y The Y coordinate of the point being tested for containment
+ * @return true iff (x,y) are contained by the rectangle, where containment
+ * means left <= x < right and top <= y < bottom
+ */
+ public boolean contains(float x, float y) {
+ return left < right && top < bottom // check for empty first
+ && x >= left && x < right && y >= top && y < bottom;
+ }
+
+ /**
+ * Returns true iff the 4 specified sides of a rectangle are inside or equal
+ * to this rectangle. i.e. is this rectangle a superset of the specified
+ * rectangle. An empty rectangle never contains another rectangle.
+ *
+ * @param left The left side of the rectangle being tested for containment
+ * @param top The top of the rectangle being tested for containment
+ * @param right The right side of the rectangle being tested for containment
+ * @param bottom The bottom of the rectangle being tested for containment
+ * @return true iff the the 4 specified sides of a rectangle are inside or
+ * equal to this rectangle
+ */
+ public boolean contains(float left, float top, float right, float bottom) {
+ // check for empty first
+ return this.left < this.right && this.top < this.bottom
+ // now check for containment
+ && this.left <= left && this.top <= top
+ && this.right >= right && this.bottom >= bottom;
+ }
+
+ /**
+ * Returns true iff the specified rectangle r is inside or equal to this
+ * rectangle. An empty rectangle never contains another rectangle.
+ *
+ * @param r The rectangle being tested for containment.
+ * @return true iff the specified rectangle r is inside or equal to this
+ * rectangle
+ */
+ public boolean contains(RectF r) {
+ // check for empty first
+ return this.left < this.right && this.top < this.bottom
+ // now check for containment
+ && left <= r.left && top <= r.top
+ && right >= r.right && bottom >= r.bottom;
+ }
+
+ /**
+ * If the rectangle specified by left,top,right,bottom intersects this
+ * rectangle, return true and set this rectangle to that intersection,
+ * otherwise return false and do not change this rectangle. No check is
+ * performed to see if either rectangle is empty. Note: To just test for
+ * intersection, use intersects()
+ *
+ * @param left The left side of the rectangle being intersected with this
+ * rectangle
+ * @param top The top of the rectangle being intersected with this rectangle
+ * @param right The right side of the rectangle being intersected with this
+ * rectangle.
+ * @param bottom The bottom of the rectangle being intersected with this
+ * rectangle.
+ * @return true if the specified rectangle and this rectangle intersect
+ * (and this rectangle is then set to that intersection) else
+ * return false and do not change this rectangle.
+ */
+ public boolean intersect(float left, float top, float right, float bottom) {
+ if (this.left < right && left < this.right
+ && this.top < bottom && top < this.bottom) {
+ if (this.left < left) {
+ this.left = left;
+ }
+ if (this.top < top) {
+ this.top = top;
+ }
+ if (this.right > right) {
+ this.right = right;
+ }
+ if (this.bottom > bottom) {
+ this.bottom = bottom;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * If the specified rectangle intersects this rectangle, return true and set
+ * this rectangle to that intersection, otherwise return false and do not
+ * change this rectangle. No check is performed to see if either rectangle
+ * is empty. To just test for intersection, use intersects()
+ *
+ * @param r The rectangle being intersected with this rectangle.
+ * @return true if the specified rectangle and this rectangle intersect
+ * (and this rectangle is then set to that intersection) else
+ * return false and do not change this rectangle.
+ */
+ public boolean intersect(RectF r) {
+ return intersect(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * If rectangles a and b intersect, return true and set this rectangle to
+ * that intersection, otherwise return false and do not change this
+ * rectangle. No check is performed to see if either rectangle is empty.
+ * To just test for intersection, use intersects()
+ *
+ * @param a The first rectangle being intersected with
+ * @param b The second rectangle being intersected with
+ * @return true iff the two specified rectangles intersect. If they do, set
+ * this rectangle to that intersection. If they do not, return
+ * false and do not change this rectangle.
+ */
+ public boolean setIntersect(RectF a, RectF b) {
+ if (a.left < b.right && b.left < a.right
+ && a.top < b.bottom && b.top < a.bottom) {
+ left = Math.max(a.left, b.left);
+ top = Math.max(a.top, b.top);
+ right = Math.min(a.right, b.right);
+ bottom = Math.min(a.bottom, b.bottom);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this rectangle intersects the specified rectangle.
+ * In no event is this rectangle modified. No check is performed to see
+ * if either rectangle is empty. To record the intersection, use intersect()
+ * or setIntersect().
+ *
+ * @param left The left side of the rectangle being tested for intersection
+ * @param top The top of the rectangle being tested for intersection
+ * @param right The right side of the rectangle being tested for
+ * intersection
+ * @param bottom The bottom of the rectangle being tested for intersection
+ * @return true iff the specified rectangle intersects this rectangle. In
+ * no event is this rectangle modified.
+ */
+ public boolean intersects(float left, float top, float right,
+ float bottom) {
+ return this.left < right && left < this.right
+ && this.top < bottom && top < this.bottom;
+ }
+
+ /**
+ * Returns true iff the two specified rectangles intersect. In no event are
+ * either of the rectangles modified. To record the intersection,
+ * use intersect() or setIntersect().
+ *
+ * @param a The first rectangle being tested for intersection
+ * @param b The second rectangle being tested for intersection
+ * @return true iff the two specified rectangles intersect. In no event are
+ * either of the rectangles modified.
+ */
+ public static boolean intersects(RectF a, RectF b) {
+ return a.left < b.right && b.left < a.right
+ && a.top < b.bottom && b.top < a.bottom;
+ }
+
+ /**
+ * Set the dst integer Rect by rounding this rectangle's coordinates
+ * to their nearest integer values.
+ */
+ public void round(Rect dst) {
+ dst.set(FastMath.round(left), FastMath.round(top),
+ FastMath.round(right), FastMath.round(bottom));
+ }
+
+ /**
+ * Set the dst integer Rect by rounding "out" this rectangle, choosing the
+ * floor of top and left, and the ceiling of right and bottom.
+ */
+ public void roundOut(Rect dst) {
+ dst.set((int) FloatMath.floor(left), (int) FloatMath.floor(top),
+ (int) FloatMath.ceil(right), (int) FloatMath.ceil(bottom));
+ }
+
+ /**
+ * Update this Rect to enclose itself and the specified rectangle. If the
+ * specified rectangle is empty, nothing is done. If this rectangle is empty
+ * it is set to the specified rectangle.
+ *
+ * @param left The left edge being unioned with this rectangle
+ * @param top The top edge being unioned with this rectangle
+ * @param right The right edge being unioned with this rectangle
+ * @param bottom The bottom edge being unioned with this rectangle
+ */
+ public void union(float left, float top, float right, float bottom) {
+ if ((left < right) && (top < bottom)) {
+ if ((this.left < this.right) && (this.top < this.bottom)) {
+ if (this.left > left)
+ this.left = left;
+ if (this.top > top)
+ this.top = top;
+ if (this.right < right)
+ this.right = right;
+ if (this.bottom < bottom)
+ this.bottom = bottom;
+ } else {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+ }
+ }
+
+ /**
+ * Update this Rect to enclose itself and the specified rectangle. If the
+ * specified rectangle is empty, nothing is done. If this rectangle is empty
+ * it is set to the specified rectangle.
+ *
+ * @param r The rectangle being unioned with this rectangle
+ */
+ public void union(RectF r) {
+ union(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Update this Rect to enclose itself and the [x,y] coordinate. There is no
+ * check to see that this rectangle is non-empty.
+ *
+ * @param x The x coordinate of the point to add to the rectangle
+ * @param y The y coordinate of the point to add to the rectangle
+ */
+ public void union(float x, float y) {
+ if (x < left) {
+ left = x;
+ } else if (x > right) {
+ right = x;
+ }
+ if (y < top) {
+ top = y;
+ } else if (y > bottom) {
+ bottom = y;
+ }
+ }
+
+ /**
+ * Swap top/bottom or left/right if there are flipped (i.e. left > right
+ * and/or top > bottom). This can be called if
+ * the edges are computed separately, and may have crossed over each other.
+ * If the edges are already correct (i.e. left <= right and top <= bottom)
+ * then nothing is done.
+ */
+ public void sort() {
+ if (left > right) {
+ float temp = left;
+ left = right;
+ right = temp;
+ }
+ if (top > bottom) {
+ float temp = top;
+ top = bottom;
+ bottom = temp;
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/Region.aidl b/graphics/java/android/graphics/Region.aidl
new file mode 100644
index 0000000..7d1286f
--- /dev/null
+++ b/graphics/java/android/graphics/Region.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/graphics/Rect.aidl
+**
+** Copyright 2007, 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;
+
+parcelable Region;
diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java
new file mode 100644
index 0000000..544ff4f
--- /dev/null
+++ b/graphics/java/android/graphics/Region.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2006 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 android.os.Parcel;
+import android.os.Parcelable;
+
+public class Region implements Parcelable {
+
+ // the native values for these must match up with the enum in SkRegion.h
+ public enum Op {
+ DIFFERENCE(0),
+ INTERSECT(1),
+ UNION(2),
+ XOR(3),
+ REVERSE_DIFFERENCE(4),
+ REPLACE(5);
+
+ Op(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /** Create an empty region
+ */
+ public Region() {
+ this(nativeConstructor());
+ }
+
+ /** Return a copy of the specified region
+ */
+ public Region(Region region) {
+ this(nativeConstructor());
+ nativeSetRegion(mNativeRegion, region.mNativeRegion);
+ }
+
+ /** Return a region set to the specified rectangle
+ */
+ public Region(Rect r) {
+ mNativeRegion = nativeConstructor();
+ nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
+ }
+
+ /** Return a region set to the specified rectangle
+ */
+ public Region(int left, int top, int right, int bottom) {
+ mNativeRegion = nativeConstructor();
+ nativeSetRect(mNativeRegion, left, top, right, bottom);
+ }
+
+ /** Set the region to the empty region
+ */
+ public void setEmpty() {
+ nativeSetRect(mNativeRegion, 0, 0, 0, 0);
+ }
+
+ /** Set the region to the specified region.
+ */
+ public boolean set(Region region) {
+ return nativeSetRegion(mNativeRegion, region.mNativeRegion);
+ }
+
+ /** Set the region to the specified rectangle
+ */
+ public boolean set(Rect r) {
+ return nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
+ }
+
+ /** Set the region to the specified rectangle
+ */
+ public boolean set(int left, int top, int right, int bottom) {
+ return nativeSetRect(mNativeRegion, left, top, right, bottom);
+ }
+
+ /**
+ * Set the region to the area described by the path and clip.
+ * Return true if the resulting region is non-empty. This produces a region
+ * that is identical to the pixels that would be drawn by the path
+ * (with no antialiasing).
+ */
+ public boolean setPath(Path path, Region clip) {
+ return nativeSetPath(mNativeRegion, path.ni(), clip.mNativeRegion);
+ }
+
+ /**
+ * Return true if this region is empty
+ */
+ public native boolean isEmpty();
+
+ /**
+ * Return true if the region contains a single rectangle
+ */
+ public native boolean isRect();
+
+ /**
+ * Return true if the region contains more than one rectangle
+ */
+ public native boolean isComplex();
+
+ /**
+ * Return a new Rect set to the bounds of the region. If the region is
+ * empty, the Rect will be set to [0, 0, 0, 0]
+ */
+ public Rect getBounds() {
+ Rect r = new Rect();
+ nativeGetBounds(mNativeRegion, r);
+ return r;
+ }
+
+ /**
+ * Set the Rect to the bounds of the region. If the region is empty, the
+ * Rect will be set to [0, 0, 0, 0]
+ */
+ public boolean getBounds(Rect r) {
+ if (r == null) {
+ throw new NullPointerException();
+ }
+ return nativeGetBounds(mNativeRegion, r);
+ }
+
+ /**
+ * Return the boundary of the region as a new Path. If the region is empty,
+ * the path will also be empty.
+ */
+ public Path getBoundaryPath() {
+ Path path = new Path();
+ nativeGetBoundaryPath(mNativeRegion, path.ni());
+ return path;
+ }
+
+ /**
+ * Set the path to the boundary of the region. If the region is empty, the
+ * path will also be empty.
+ */
+ public boolean getBoundaryPath(Path path) {
+ return nativeGetBoundaryPath(mNativeRegion, path.ni());
+ }
+
+ /**
+ * Return true if the region contains the specified point
+ */
+ public native boolean contains(int x, int y);
+
+ /**
+ * Return true if the region is a single rectangle (not complex) and it
+ * contains the specified rectangle. Returning false is not a guarantee
+ * that the rectangle is not contained by this region, but return true is a
+ * guarantee that the rectangle is contained by this region.
+ */
+ public boolean quickContains(Rect r) {
+ return quickContains(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Return true if the region is a single rectangle (not complex) and it
+ * contains the specified rectangle. Returning false is not a guarantee
+ * that the rectangle is not contained by this region, but return true is a
+ * guarantee that the rectangle is contained by this region.
+ */
+ public native boolean quickContains(int left, int top, int right,
+ int bottom);
+
+ /**
+ * Return true if the region is empty, or if the specified rectangle does
+ * not intersect the region. Returning false is not a guarantee that they
+ * intersect, but returning true is a guarantee that they do not.
+ */
+ public boolean quickReject(Rect r) {
+ return quickReject(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Return true if the region is empty, or if the specified rectangle does
+ * not intersect the region. Returning false is not a guarantee that they
+ * intersect, but returning true is a guarantee that they do not.
+ */
+ public native boolean quickReject(int left, int top, int right, int bottom);
+
+ /**
+ * Return true if the region is empty, or if the specified region does not
+ * intersect the region. Returning false is not a guarantee that they
+ * intersect, but returning true is a guarantee that they do not.
+ */
+ public native boolean quickReject(Region rgn);
+
+ /**
+ * Translate the region by [dx, dy]. If the region is empty, do nothing.
+ */
+ public void translate(int dx, int dy) {
+ translate(dx, dy, null);
+ }
+
+ /**
+ * Set the dst region to the result of translating this region by [dx, dy].
+ * If this region is empty, then dst will be set to empty.
+ */
+ public native void translate(int dx, int dy, Region dst);
+
+ public final boolean union(Rect r) {
+ return op(r, Op.UNION);
+ }
+
+ /**
+ * Perform the specified Op on this region and the specified rect. Return
+ * true if the result of the op is not empty.
+ */
+ public boolean op(Rect r, Op op) {
+ return nativeOp(mNativeRegion, r.left, r.top, r.right, r.bottom,
+ op.nativeInt);
+ }
+
+ /**
+ * Perform the specified Op on this region and the specified rect. Return
+ * true if the result of the op is not empty.
+ */
+ public boolean op(int left, int top, int right, int bottom, Op op) {
+ return nativeOp(mNativeRegion, left, top, right, bottom,
+ op.nativeInt);
+ }
+
+ /**
+ * Perform the specified Op on this region and the specified region. Return
+ * true if the result of the op is not empty.
+ */
+ public boolean op(Region region, Op op) {
+ return op(this, region, op);
+ }
+
+ /**
+ * Set this region to the result of performing the Op on the specified rect
+ * and region. Return true if the result is not empty.
+ */
+ public boolean op(Rect rect, Region region, Op op) {
+ return nativeOp(mNativeRegion, rect, region.mNativeRegion,
+ op.nativeInt);
+ }
+
+ /**
+ * Set this region to the result of performing the Op on the specified
+ * regions. Return true if the result is not empty.
+ */
+ public boolean op(Region region1, Region region2, Op op) {
+ return nativeOp(mNativeRegion, region1.mNativeRegion,
+ region2.mNativeRegion, op.nativeInt);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+
+ public static final Parcelable.Creator<Region> CREATOR
+ = new Parcelable.Creator<Region>() {
+ /**
+ * Rebuild a Region previously stored with writeToParcel().
+ * @param p Parcel object to read the region from
+ * @return a new region created from the data in the parcel
+ */
+ public Region createFromParcel(Parcel p) {
+ int ni = nativeCreateFromParcel(p);
+ if (ni == 0) {
+ throw new RuntimeException();
+ }
+ return new Region(ni);
+ }
+ public Region[] newArray(int size) {
+ return new Region[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write the region and its pixels to the parcel. The region can be
+ * rebuilt from the parcel by calling CREATOR.createFromParcel().
+ * @param p Parcel object to write the region data into
+ */
+ public void writeToParcel(Parcel p, int flags) {
+ if (!nativeWriteToParcel(mNativeRegion, p)) {
+ throw new RuntimeException();
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ nativeDestructor(mNativeRegion);
+ }
+
+ /*package*/ Region(int ni) {
+ if (ni == 0) {
+ throw new RuntimeException();
+ }
+ mNativeRegion = ni;
+ }
+
+ /* add dummy parameter so constructor can be called from jni without
+ triggering 'not cloneable' exception */
+ private Region(int ni, int dummy) {
+ this(ni);
+ }
+
+ /*package*/ final int ni() {
+ return mNativeRegion;
+ }
+
+ private static native int nativeConstructor();
+ private static native void nativeDestructor(int native_region);
+
+ private static native boolean nativeSetRegion(int native_dst,
+ int native_src);
+ private static native boolean nativeSetRect(int native_dst, int left,
+ int top, int right, int bottom);
+ private static native boolean nativeSetPath(int native_dst, int native_path,
+ int native_clip);
+ private static native boolean nativeGetBounds(int native_region, Rect rect);
+ private static native boolean nativeGetBoundaryPath(int native_region,
+ int native_path);
+
+ private static native boolean nativeOp(int native_dst, int left, int top,
+ int right, int bottom, int op);
+ private static native boolean nativeOp(int native_dst, Rect rect,
+ int native_region, int op);
+ private static native boolean nativeOp(int native_dst, int native_region1,
+ int native_region2, int op);
+
+ private static native int nativeCreateFromParcel(Parcel p);
+ private static native boolean nativeWriteToParcel(int native_region,
+ Parcel p);
+
+ private final int mNativeRegion;
+}
diff --git a/graphics/java/android/graphics/RegionIterator.java b/graphics/java/android/graphics/RegionIterator.java
new file mode 100644
index 0000000..817f853
--- /dev/null
+++ b/graphics/java/android/graphics/RegionIterator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 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;
+
+public class RegionIterator {
+
+ /**
+ * Construct an iterator for all of the rectangles in a region. This
+ * effectively makes a private copy of the region, so any subsequent edits
+ * to region will not affect the iterator.
+ *
+ * @param region the region that will be iterated
+ */
+ public RegionIterator(Region region) {
+ mNativeIter = nativeConstructor(region.ni());
+ }
+
+ /**
+ * Return the next rectangle in the region. If there are no more rectangles
+ * this returns false and r is unchanged. If there is at least one more,
+ * this returns true and r is set to that rectangle.
+ */
+ public final boolean next(Rect r) {
+ if (r == null) {
+ throw new NullPointerException("The Rect must be provided");
+ }
+ return nativeNext(mNativeIter, r);
+ }
+
+ protected void finalize() throws Throwable {
+ nativeDestructor(mNativeIter);
+ }
+
+ private static native int nativeConstructor(int native_region);
+ private static native void nativeDestructor(int native_iter);
+ private static native boolean nativeNext(int native_iter, Rect r);
+
+ private final int mNativeIter;
+}
+
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
new file mode 100644
index 0000000..ae0304e
--- /dev/null
+++ b/graphics/java/android/graphics/Shader.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 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;
+
+/**
+ * Shader is the based class for objects that return horizontal spans of colors
+ * during drawing. A subclass of Shader is installed in a Paint calling
+ * paint.setShader(shader). After that any object (other than a bitmap) that is
+ * drawn with that paint will get its color(s) from the shader.
+ */
+public class Shader {
+
+ // this is set by subclasses, but don't make it public
+ /* package */ int native_instance;
+
+ public enum TileMode {
+ /**
+ * replicate the edge color if the shader draws outside of its
+ * original bounds
+ */
+ CLAMP (0),
+ /**
+ * repeat the shader's image horizontally and vertically
+ */
+ REPEAT (1),
+ /**
+ * repeat the shader's image horizontally and vertically, alternating
+ * mirror images so that adjacent images always seam
+ */
+ MIRROR (2);
+
+ TileMode(int nativeInt) {
+ this.nativeInt = nativeInt;
+ }
+ final int nativeInt;
+ }
+
+ /**
+ * Return true if the shader has a non-identity local matrix.
+ * @param localM If not null, it is set to the shader's local matrix.
+ * @return true if the shader has a non-identity local matrix
+ */
+ public boolean getLocalMatrix(Matrix localM) {
+ return nativeGetLocalMatrix(native_instance, localM.native_instance);
+ }
+
+ /**
+ * Set the shader's local matrix. Passing null will reset the shader's
+ * matrix to identity
+ * @param localM The shader's new local matrix, or null to specify identity
+ */
+ public void setLocalMatrix(Matrix localM) {
+ nativeSetLocalMatrix(native_instance,
+ localM != null ? localM.native_instance : 0);
+ }
+
+ protected void finalize() throws Throwable {
+ nativeDestructor(native_instance);
+ }
+
+ private static native void nativeDestructor(int native_shader);
+ private static native boolean nativeGetLocalMatrix(int native_shader,
+ int matrix_instance);
+ private static native void nativeSetLocalMatrix(int native_shader,
+ int matrix_instance);
+}
diff --git a/graphics/java/android/graphics/SumPathEffect.java b/graphics/java/android/graphics/SumPathEffect.java
new file mode 100644
index 0000000..cc7c778
--- /dev/null
+++ b/graphics/java/android/graphics/SumPathEffect.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class SumPathEffect extends PathEffect {
+
+ /**
+ * Construct a PathEffect whose effect is to apply two effects, in sequence.
+ * (e.g. first(path) + second(path))
+ */
+ public SumPathEffect(PathEffect first, PathEffect second) {
+ native_instance = nativeCreate(first.native_instance,
+ second.native_instance);
+ }
+
+ private static native int nativeCreate(int first, int second);
+}
+
diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java
new file mode 100644
index 0000000..7456993
--- /dev/null
+++ b/graphics/java/android/graphics/SweepGradient.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 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;
+
+public class SweepGradient extends Shader {
+
+ /**
+ * A subclass of Shader that draws a sweep gradient around a center point.
+ *
+ * @param cx The x-coordinate of the center
+ * @param cy The y-coordinate of the center
+ * @param colors The colors to be distributed between around the center.
+ * There must be at least 2 colors in the array.
+ * @param positions May be NULL. The relative position of
+ * each corresponding color in the colors array, beginning
+ * with 0 and ending with 1.0. If the values are not
+ * monotonic, the drawing may produce unexpected results.
+ * If positions is NULL, then the colors are automatically
+ * spaced evenly.
+ */
+ public SweepGradient(float cx, float cy,
+ int colors[], float positions[]) {
+ if (colors.length < 2) {
+ throw new IllegalArgumentException("needs >= 2 number of colors");
+ }
+ if (positions != null && colors.length != positions.length) {
+ throw new IllegalArgumentException(
+ "color and position arrays must be of equal length");
+ }
+ native_instance = nativeCreate1(cx, cy, colors, positions);
+ }
+
+ /**
+ * A subclass of Shader that draws a sweep gradient around a center point.
+ *
+ * @param cx The x-coordinate of the center
+ * @param cy The y-coordinate of the center
+ * @param color0 The color to use at the start of the sweep
+ * @param color1 The color to use at the end of the sweep
+ */
+ public SweepGradient(float cx, float cy, int color0, int color1) {
+ native_instance = nativeCreate2(cx, cy, color0, color1);
+ }
+
+ private static native int nativeCreate1(float x, float y,
+ int colors[], float positions[]);
+ private static native int nativeCreate2(float x, float y,
+ int color0, int color1);
+}
+
diff --git a/graphics/java/android/graphics/TemporaryBuffer.java b/graphics/java/android/graphics/TemporaryBuffer.java
new file mode 100644
index 0000000..1d7fe01
--- /dev/null
+++ b/graphics/java/android/graphics/TemporaryBuffer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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.internal.util.ArrayUtils;
+
+/* package */ class TemporaryBuffer
+{
+ /* package */ static char[] obtain(int len) {
+ char[] buf;
+
+ synchronized (TemporaryBuffer.class) {
+ buf = sTemp;
+ sTemp = null;
+ }
+
+ if (buf == null || buf.length < len)
+ buf = new char[ArrayUtils.idealCharArraySize(len)];
+
+ return buf;
+ }
+
+ /* package */ static void recycle(char[] temp) {
+ if (temp.length > 1000)
+ return;
+
+ synchronized (TemporaryBuffer.class) {
+ sTemp = temp;
+ }
+ }
+
+ private static char[] sTemp = null;
+}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
new file mode 100644
index 0000000..c69c92c
--- /dev/null
+++ b/graphics/java/android/graphics/Typeface.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2006 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 android.content.res.AssetManager;
+
+/**
+ * The Typeface class specifies the typeface and intrinsic style of a font.
+ * This is used in the paint, along with optionally Paint settings like
+ * textSize, textSkewX, textScaleX to specify
+ * how text appears when drawn (and measured).
+ */
+public class Typeface {
+
+ /** The default NORMAL typeface object */
+ public static final Typeface DEFAULT;
+ /**
+ * The default BOLD typeface object. Note: this may be not actually be
+ * bold, depending on what fonts are installed. Call getStyle() to know
+ * for sure.
+ */
+ public static final Typeface DEFAULT_BOLD;
+ /** The NORMAL style of the default sans serif typeface. */
+ public static final Typeface SANS_SERIF;
+ /** The NORMAL style of the default serif typeface. */
+ public static final Typeface SERIF;
+ /** The NORMAL style of the default monospace typeface. */
+ public static final Typeface MONOSPACE;
+
+ private static Typeface[] sDefaults;
+
+ /* package */ int native_instance;
+
+ // Style
+ public static final int NORMAL = 0;
+ public static final int BOLD = 1;
+ public static final int ITALIC = 2;
+ public static final int BOLD_ITALIC = 3;
+
+ /** Returns the typeface's intrinsic style attributes */
+ public int getStyle() {
+ return nativeGetStyle(native_instance);
+ }
+
+ /** Returns true if getStyle() has the BOLD bit set. */
+ public final boolean isBold() {
+ return (getStyle() & BOLD) != 0;
+ }
+
+ /** Returns true if getStyle() has the ITALIC bit set. */
+ public final boolean isItalic() {
+ return (getStyle() & ITALIC) != 0;
+ }
+
+ /**
+ * Create a typeface object given a family name, and option style information.
+ * If null is passed for the name, then the "default" font will be chosen.
+ * The resulting typeface object can be queried (getStyle()) to discover what
+ * its "real" style characteristics are.
+ *
+ * @param familyName May be null. The name of the font family.
+ * @param style The style (normal, bold, italic) of the typeface.
+ * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
+ * @return The best matching typeface.
+ */
+ public static Typeface create(String familyName, int style) {
+ return new Typeface(nativeCreate(familyName, style));
+ }
+
+ /**
+ * Create a typeface object that best matches the specified existing
+ * typeface and the specified Style. Use this call if you want to pick a new
+ * style from the same family of an existing typeface object. If family is
+ * null, this selects from the default font's family.
+ *
+ * @param family May be null. The name of the existing type face.
+ * @param style The style (normal, bold, italic) of the typeface.
+ * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
+ * @return The best matching typeface.
+ */
+ public static Typeface create(Typeface family, int style) {
+ int ni = 0;
+ if (family != null) {
+ ni = family.native_instance;
+ }
+ return new Typeface(nativeCreateFromTypeface(ni, style));
+ }
+
+ /**
+ * Returns one of the default typeface objects, based on the specified style
+ *
+ * @return the default typeface that corresponds to the style
+ */
+ public static Typeface defaultFromStyle(int style) {
+ return sDefaults[style];
+ }
+
+ /**
+ * Create a new typeface from the specified font data.
+ * @param mgr The application's asset manager
+ * @param path The file name of the font data in the assets directory
+ * @return The new typeface.
+ */
+ public static Typeface createFromAsset(AssetManager mgr, String path) {
+ return new Typeface(nativeCreateFromAsset(mgr, path));
+ }
+
+ // don't allow clients to call this directly
+ private Typeface(int ni) {
+ native_instance = ni;
+ }
+
+ static {
+ DEFAULT = create((String)null, 0);
+ DEFAULT_BOLD = create((String)null, Typeface.BOLD);
+ SANS_SERIF = create("sans-serif", 0);
+ SERIF = create("serif", 0);
+ MONOSPACE = create("monospace", 0);
+
+ sDefaults = new Typeface[] {
+ DEFAULT,
+ DEFAULT_BOLD,
+ create((String)null, Typeface.ITALIC),
+ create((String)null, Typeface.BOLD_ITALIC),
+ };
+ }
+
+ protected void finalize() throws Throwable {
+ nativeUnref(native_instance);
+ }
+
+ private static native int nativeCreate(String familyName, int style);
+ private static native int nativeCreateFromTypeface(int native_instance,
+ int style);
+ private static native void nativeUnref(int native_instance);
+ private static native int nativeGetStyle(int native_instance);
+ private static native int nativeCreateFromAsset(AssetManager mgr,
+ String path);
+}
diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java
new file mode 100644
index 0000000..42c410e
--- /dev/null
+++ b/graphics/java/android/graphics/Xfermode.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+// This file was generated from the C++ include file: SkXfermode.h
+// Any changes made to this file will be discarded by the build.
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// or one of the auxilary file specifications in device/tools/gluemaker.
+
+package android.graphics;
+
+/**
+ * Xfermode is the base class for objects that are called to implement custom
+ * "transfer-modes" in the drawing pipeline. The static function Create(Modes)
+ * can be called to return an instance of any of the predefined subclasses as
+ * specified in the Modes enum. When an Xfermode is assigned to an Paint, then
+ * objects drawn with that paint have the xfermode applied.
+ */
+public class Xfermode {
+
+ protected void finalize() throws Throwable {
+ finalizer(native_instance);
+ }
+
+ private static native void finalizer(int native_instance);
+
+ int native_instance;
+}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
new file mode 100644
index 0000000..26e50cd
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+
+/**
+ *
+ * An object used to define frame-by-frame animations that can be used as a View object's
+ * background.
+ * <p>Each frame in a frame-by-frame animation is a drawable
+ * <a href="{@docRoot}devel/resources-i18n.html">resource</a>.
+ * The simplest way to create a frame-by-frame animation is to define the animation in an XML
+ * file in the drawable/ folder, set it as the background to a View object, then call
+ * AnimationDrawable.run() to start the animation, as shown here. More details about the
+ * format of the animation XML file are given in
+ * <a href="{@docRoot}reference/available-resources.html#animationdrawable">Frame by Frame
+ * Animation</a>.
+ * spin_animation.xml file in res/drawable/ folder:</p>
+ * <pre>&lt;!-- Animation frames are wheel0.png -- wheel5.png files inside the
+ * res/drawable/ folder --&gt;
+ * &lt;animation-list android:id=&quot;selected&quot; android:oneshot=&quot;false&quot;&gt;
+ * &lt;item android:drawable=&quot;@drawable/wheel0&quot; android:duration=&quot;50&quot; /&gt;
+ * &lt;item android:drawable=&quot;@drawable/wheel1&quot; android:duration=&quot;50&quot; /&gt;
+ * &lt;item android:drawable=&quot;@drawable/wheel2&quot; android:duration=&quot;50&quot; /&gt;
+ * &lt;item android:drawable=&quot;@drawable/wheel3&quot; android:duration=&quot;50&quot; /&gt;
+ * &lt;item android:drawable=&quot;@drawable/wheel4&quot; android:duration=&quot;50&quot; /&gt;
+ * &lt;item android:drawable=&quot;@drawable/wheel5&quot; android:duration=&quot;50&quot; /&gt;
+ * &lt;/animation-list&gt;</pre>
+ *
+ * <p>Here is the code to load and play this animation.</p>
+ * <pre>// Load the ImageView that will host the animation and
+ * // set its background to our AnimationDrawable XML resource.
+ * ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
+ * img.setBackgroundResource(R.drawable.spin_animation);
+ *
+ * // Get the background, which has been compiled to an AnimationDrawable object.
+ * AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();
+ *
+ * // Start the animation (looped playback by default).
+ * frameAnimation.start()
+ * </pre>
+ */
+public class AnimationDrawable extends DrawableContainer implements Runnable {
+ public AnimationDrawable() {
+ this(null);
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ boolean changed = super.setVisible(visible, restart);
+ if (visible) {
+ if (changed || restart) {
+ setFrame(0, true, true);
+ }
+ } else {
+ unscheduleSelf(this);
+ }
+ return changed;
+ }
+
+ /**
+ * <p>Starts the animation, looping if necessary. This method has no effect
+ * if the animation is running.</p>
+ *
+ * @see #isRunning()
+ * @see #stop()
+ */
+ public void start() {
+ if (!isRunning()) {
+ run();
+ }
+ }
+
+ /**
+ * <p>Stops the animation. This method has no effect if the animation is
+ * not running.</p>
+ *
+ * @see #isRunning()
+ * @see #start()
+ */
+ public void stop() {
+ if (isRunning()) {
+ unscheduleSelf(this);
+ }
+ }
+
+ /**
+ * <p>Indicates whether the animation is currently running or not.</p>
+ *
+ * @return true if the animation is running, false otherwise
+ */
+ public boolean isRunning() {
+ return mCurFrame > -1;
+ }
+
+ /**
+ * <p>This method exists for implementation purpose only and should not be
+ * called directly. Invoke {@link #start()} instead.</p>
+ *
+ * @see #start()
+ */
+ public void run() {
+ nextFrame(false);
+ }
+
+ @Override
+ public void unscheduleSelf(Runnable what) {
+ mCurFrame = -1;
+ super.unscheduleSelf(what);
+ }
+
+ /**
+ * @return The number of frames in the animation
+ */
+ public int getNumberOfFrames() {
+ return mAnimationState.getChildCount();
+ }
+
+ /**
+ * @return The Drawable at the specified frame index
+ */
+ public Drawable getFrame(int index) {
+ return mAnimationState.getChildren()[index];
+ }
+
+ /**
+ * @return The duration in milliseconds of the frame at the
+ * specified index
+ */
+ public int getDuration(int i) {
+ return mAnimationState.mDurations[i];
+ }
+
+ /**
+ * @return True of the animation will play once, false otherwise
+ */
+ public boolean isOneShot() {
+ return mAnimationState.mOneShot;
+ }
+
+ /**
+ * Sets whether the animation should play once or repeat.
+ *
+ * @param oneShot Pass true if the animation should only play once
+ */
+ public void setOneShot(boolean oneShot) {
+ mAnimationState.mOneShot = oneShot;
+ }
+
+ /**
+ * Add a frame to the animation
+ *
+ * @param frame The frame to add
+ * @param duration How long in milliseconds the frame should appear
+ */
+ public void addFrame(Drawable frame, int duration) {
+ mAnimationState.addFrame(frame, duration);
+ }
+
+ private void nextFrame(boolean unschedule) {
+ int next = mCurFrame+1;
+ final int N = mAnimationState.getChildCount();
+ if (next >= N) {
+ next = 0;
+ }
+ setFrame(next, unschedule, !mAnimationState.mOneShot || next < (N-1));
+ }
+
+ private void setFrame(int frame, boolean unschedule, boolean animate) {
+ if (frame >= mAnimationState.getChildCount()) {
+ return;
+ }
+ mCurFrame = frame;
+ selectDrawable(frame);
+ if (unschedule) {
+ unscheduleSelf(this);
+ }
+ if (animate) {
+ scheduleSelf(this, SystemClock.uptimeMillis()
+ + mAnimationState.mDurations[frame]);
+ }
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser,
+ AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AnimationDrawable);
+
+ super.inflateWithAttributes(r, parser, a,
+ com.android.internal.R.styleable.AnimationDrawable_visible);
+
+ mAnimationState.setVariablePadding(a.getBoolean(
+ com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
+
+ mAnimationState.mOneShot = a.getBoolean(
+ com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
+
+ a.recycle();
+
+ int type;
+
+ final int innerDepth = parser.getDepth()+1;
+ int depth;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth=parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth || !parser.getName().equals("item")) {
+ continue;
+ }
+
+ a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AnimationDrawableItem);
+
+ int duration = a.getInt(
+ com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
+ if (duration < 0) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'duration' attribute");
+ }
+ int drawableRes = a.getResourceId(
+ com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0);
+
+ a.recycle();
+
+ Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ while ((type=parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ mAnimationState.addFrame(dr, duration);
+ if (dr != null) {
+ dr.setCallback(this);
+ }
+ }
+
+ setFrame(0, true, false);
+ }
+
+ private final static class AnimationState extends DrawableContainerState
+ {
+ AnimationState(AnimationState orig, AnimationDrawable owner)
+ {
+ super(orig, owner);
+
+ if (orig != null) {
+ mDurations = orig.mDurations;
+ mOneShot = orig.mOneShot;
+ } else {
+ mDurations = new int[getChildren().length];
+ mOneShot = true;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable()
+ {
+ return new AnimationDrawable(this);
+ }
+
+ public void addFrame(Drawable dr, int dur)
+ {
+ int pos = super.addChild(dr);
+ mDurations[pos] = dur;
+ }
+
+ @Override
+ public void growArray(int oldSize, int newSize)
+ {
+ super.growArray(oldSize, newSize);
+ int[] newDurations = new int[newSize];
+ System.arraycopy(mDurations, 0, newDurations, 0, oldSize);
+ mDurations = newDurations;
+ }
+
+ private int[] mDurations;
+ private boolean mOneShot;
+ }
+
+ private AnimationDrawable(AnimationState state) {
+ AnimationState as = new AnimationState(state, this);
+ mAnimationState = as;
+ setConstantState(as);
+ if (state != null) {
+ setFrame(0, true, false);
+ }
+ }
+
+ private final AnimationState mAnimationState;
+
+ private int mCurFrame = -1;
+}
+
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
new file mode 100644
index 0000000..97b44ba
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.BitmapShader;
+import android.util.AttributeSet;
+import android.view.Gravity;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class BitmapDrawable extends Drawable {
+
+ private static final int DEFAULT_PAINT_FLAGS = Paint.FILTER_BITMAP_FLAG;
+ private BitmapState mBitmapState;
+ private Bitmap mBitmap;
+ private final Rect mDstRect = new Rect(); // Gravity.apply() sets this
+
+ private boolean mApplyGravity;
+ private boolean mRebuildShader;
+
+ public BitmapDrawable() {
+ mBitmapState = new BitmapState(null);
+ }
+
+ public BitmapDrawable(Bitmap bitmap) {
+ this(new BitmapState(bitmap));
+ }
+
+ public BitmapDrawable(String filepath) {
+ this(new BitmapState(BitmapFactory.decodeFile(filepath)));
+ if (mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ }
+ }
+
+ public BitmapDrawable(java.io.InputStream is) {
+ this(new BitmapState(BitmapFactory.decodeStream(is)));
+ if (mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ }
+ }
+
+ public final Paint getPaint() {
+ return mBitmapState.mPaint;
+ }
+
+ public final Bitmap getBitmap() {
+ return mBitmap;
+ }
+
+ /** Get the gravity used to position/stretch the bitmap within its bounds.
+ See android.view.Gravity
+ * @return the gravity applied to the bitmap
+ */
+ public int getGravity() {
+ return mBitmapState.mGravity;
+ }
+
+ /** Set the gravity used to position/stretch the bitmap within its bounds.
+ See android.view.Gravity
+ * @param gravity the gravity
+ */
+ public void setGravity(int gravity) {
+ mBitmapState.mGravity = gravity;
+ mApplyGravity = true;
+ }
+
+ public void setAntiAlias(boolean aa) {
+ mBitmapState.mPaint.setAntiAlias(aa);
+ }
+
+ @Override
+ public void setFilterBitmap(boolean filter) {
+ mBitmapState.mPaint.setFilterBitmap(filter);
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ mBitmapState.mPaint.setDither(dither);
+ }
+
+ public Shader.TileMode getTileModeX() {
+ return mBitmapState.mTileModeX;
+ }
+
+ public Shader.TileMode getTileModeY() {
+ return mBitmapState.mTileModeY;
+ }
+
+ public void setTileModeX(Shader.TileMode mode) {
+ setTileModeXY(mode, mBitmapState.mTileModeY);
+ }
+
+ public final void setTileModeY(Shader.TileMode mode) {
+ setTileModeXY(mBitmapState.mTileModeX, mode);
+ }
+
+ public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
+ final BitmapState state = mBitmapState;
+ if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
+ state.mTileModeX = xmode;
+ state.mTileModeY = ymode;
+ mRebuildShader = true;
+ }
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mApplyGravity = true;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ Bitmap bitmap = mBitmap;
+ if (bitmap != null) {
+ final BitmapState state = mBitmapState;
+ if (mRebuildShader) {
+ Shader.TileMode tmx = state.mTileModeX;
+ Shader.TileMode tmy = state.mTileModeY;
+
+ if (tmx == null && tmy == null) {
+ state.mPaint.setShader(null);
+ } else {
+ Shader s = new BitmapShader(bitmap,
+ tmx == null ? Shader.TileMode.CLAMP : tmx,
+ tmy == null ? Shader.TileMode.CLAMP : tmy);
+ state.mPaint.setShader(s);
+ }
+ mRebuildShader = false;
+ copyBounds(mDstRect);
+ }
+
+ Shader shader = state.mPaint.getShader();
+ if (shader == null) {
+ if (mApplyGravity) {
+ Gravity.apply(state.mGravity, bitmap.getWidth(), bitmap.getHeight(),
+ getBounds(), mDstRect);
+ mApplyGravity = false;
+ }
+ canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
+ } else {
+ if (mApplyGravity) {
+ mDstRect.set(getBounds());
+ mApplyGravity = false;
+ }
+ canvas.drawRect(mDstRect, state.mPaint);
+ }
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mBitmapState.mPaint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mBitmapState.mPaint.setColorFilter(cf);
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.BitmapDrawable);
+
+ final int id = a.getResourceId(com.android.internal.R.styleable.BitmapDrawable_src, 0);
+ if (id == 0) {
+ throw new XmlPullParserException(parser.getPositionDescription() +
+ ": <bitmap> requires a valid src attribute");
+ }
+ final Bitmap bitmap = BitmapFactory.decodeResource(r, id);
+ if (bitmap == null) {
+ throw new XmlPullParserException(parser.getPositionDescription() +
+ ": <bitmap> requires a valid src attribute");
+ }
+ mBitmapState.mBitmap = mBitmap = bitmap;
+
+ final Paint paint = mBitmapState.mPaint;
+ paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
+ paint.isAntiAlias()));
+ paint.setFilterBitmap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_filter,
+ paint.isFilterBitmap()));
+ paint.setDither(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_dither,
+ paint.isDither()));
+ setGravity(a.getInt(com.android.internal.R.styleable.BitmapDrawable_gravity, Gravity.FILL));
+ int tileMode = a.getInt(com.android.internal.R.styleable.BitmapDrawable_tileMode, -1);
+ if (tileMode != -1) {
+ switch (tileMode) {
+ case 0:
+ setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ break;
+ case 1:
+ setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
+ break;
+ case 2:
+ setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
+ break;
+ }
+ }
+
+ a.recycle();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ Bitmap bitmap = mBitmap;
+ return bitmap != null ? bitmap.getWidth() : -1;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ Bitmap bitmap = mBitmap;
+ return bitmap != null ? bitmap.getHeight() : -1;
+ }
+
+ @Override
+ public int getOpacity() {
+ if (mBitmapState.mGravity != Gravity.FILL) {
+ return PixelFormat.TRANSLUCENT;
+ }
+ Bitmap bm = mBitmap;
+ return (bm == null || bm.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
+ PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+ }
+
+ @Override
+ public final ConstantState getConstantState() {
+ mBitmapState.mChangingConfigurations = super.getChangingConfigurations();
+ return mBitmapState;
+ }
+
+ final static class BitmapState extends ConstantState {
+ Bitmap mBitmap;
+ int mChangingConfigurations;
+ int mGravity = Gravity.FILL;
+ Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
+ Shader.TileMode mTileModeX;
+ Shader.TileMode mTileModeY;
+
+ BitmapState(Bitmap bitmap) {
+ mBitmap = bitmap;
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new BitmapDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+
+ private BitmapDrawable(BitmapState state) {
+ mBitmapState = state;
+ mBitmap = state.mBitmap;
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
new file mode 100644
index 0000000..86c0747
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.*;
+import android.view.Gravity;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * A drawable that clips another drawable based on this drawable's current
+ * level value. You can control how much the child drawable gets clipped in width
+ * and height based on the level, as well as a gravity to control where it is
+ * placed in its overall container. Most often used to implement things like
+ * progress bars.
+ */
+public class ClipDrawable extends Drawable implements Drawable.Callback {
+ private ClipState mClipState;
+ private final Rect mTmpRect = new Rect();
+
+ public static final int HORIZONTAL = 1;
+ public static final int VERTICAL = 2;
+
+ ClipDrawable() {
+ this(null);
+ }
+
+ /**
+ * @param orientation Bitwise-or of {@link #HORIZONTAL} and/or {@link #VERTICAL}
+ */
+ public ClipDrawable(Drawable drawable, int gravity, int orientation) {
+ this(null);
+
+ mClipState.mDrawable = drawable;
+ mClipState.mGravity = gravity;
+ mClipState.mOrientation = orientation;
+
+ if (drawable != null) {
+ drawable.setCallback(this);
+ }
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ int type;
+
+ TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ClipDrawable);
+
+ int orientation = a.getInt(
+ com.android.internal.R.styleable.ClipDrawable_clipOrientation,
+ HORIZONTAL);
+ int g = a.getInt(com.android.internal.R.styleable.ClipDrawable_gravity, Gravity.LEFT);
+ Drawable dr = a.getDrawable(com.android.internal.R.styleable.ClipDrawable_drawable);
+
+ a.recycle();
+
+ final int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ if (dr == null) {
+ throw new IllegalArgumentException("No drawable specified for <clip>");
+ }
+
+ mClipState.mDrawable = dr;
+ mClipState.mOrientation = orientation;
+ mClipState.mGravity = g;
+ if (dr != null) {
+ dr.setCallback(this);
+ }
+ }
+
+ // overrides from Drawable.Callback
+
+ public void invalidateDrawable(Drawable who) {
+ if (mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ // overrides from Drawable
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mClipState.mChangingConfigurations
+ | mClipState.mDrawable.getChangingConfigurations();
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ // XXX need to adjust padding!
+ return mClipState.mDrawable.getPadding(padding);
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ mClipState.mDrawable.setVisible(visible, restart);
+ return super.setVisible(visible, restart);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mClipState.mDrawable.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mClipState.mDrawable.setColorFilter(cf);
+ }
+
+ @Override
+ public int getOpacity() {
+ return mClipState.mDrawable.getOpacity();
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mClipState.mDrawable.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ boolean changed = mClipState.mDrawable.setState(state);
+ return changed;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ mClipState.mDrawable.setLevel(level);
+ invalidateSelf();
+ return true;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mClipState.mDrawable.setBounds(bounds);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+
+ if (mClipState.mDrawable.getLevel() == 0) {
+ return;
+ }
+
+ final Rect r = mTmpRect;
+ final Rect bounds = getBounds();
+ int level = getLevel();
+ int w = bounds.width();
+ final int iw = 0; //mClipState.mDrawable.getIntrinsicWidth();
+ if ((mClipState.mOrientation & HORIZONTAL) != 0) {
+ w -= (w - iw) * (10000 - level) / 10000;
+ }
+ int h = bounds.height();
+ final int ih = 0; //mClipState.mDrawable.getIntrinsicHeight();
+ if ((mClipState.mOrientation & VERTICAL) != 0) {
+ h -= (h - ih) * (10000 - level) / 10000;
+ }
+ Gravity.apply(mClipState.mGravity, w, h, bounds, r);
+
+ if (w > 0 && h > 0) {
+ canvas.save();
+ canvas.clipRect(r);
+ mClipState.mDrawable.draw(canvas);
+ canvas.restore();
+ }
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mClipState.mDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mClipState.mDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mClipState.canConstantState()) {
+ mClipState.mChangingConfigurations = super.getChangingConfigurations();
+ return mClipState;
+ }
+ return null;
+ }
+
+ final static class ClipState extends ConstantState {
+ ClipState(ClipState orig, ClipDrawable owner) {
+ if (orig != null) {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ mDrawable.setCallback(owner);
+ mOrientation = orig.mOrientation;
+ mGravity = orig.mGravity;
+ mCheckedConstantState = mCanConstantState = true;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new ClipDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ boolean canConstantState() {
+ if (!mCheckedConstantState) {
+ mCanConstantState = mDrawable.getConstantState() != null;
+ mCheckedConstantState = true;
+ }
+
+ return mCanConstantState;
+ }
+
+ Drawable mDrawable;
+ int mChangingConfigurations;
+ int mOrientation;
+ int mGravity;
+
+ private boolean mCheckedConstantState;
+ private boolean mCanConstantState;
+ }
+
+ private ClipDrawable(ClipState state) {
+ mClipState = new ClipState(state, this);
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
new file mode 100644
index 0000000..4f4eda6
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -0,0 +1,150 @@
+/*
+ * 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.drawable;
+
+import android.graphics.*;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * A ColorDrawable is a specialized drawable that fills the Canvas with a specified color,
+ * and with respect to the clip region. Note that a ColorDrawable ignores the ColorFilter.
+ * It also ignores the Bounds, meaning it will draw everywhere in the current clip,
+ * even if setBounds(...) was called with a smaller area.
+ */
+public class ColorDrawable extends Drawable {
+ private ColorState mState;
+
+ /**
+ * Creates a new black ColorDrawable.
+ */
+ public ColorDrawable() {
+ this(null);
+ }
+
+ /**
+ * Creates a new ColorDrawable with the specified color.
+ *
+ * @param color The color to draw.
+ */
+ public ColorDrawable(int color) {
+ this(null);
+ mState.mBaseColor = mState.mUseColor = color;
+ }
+
+ private ColorDrawable(ColorState state) {
+ mState = new ColorState(state);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mState.mChangingConfigurations;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawColor(mState.mUseColor);
+ }
+
+ /**
+ * Returns the alpha value of this drawable's color.
+ *
+ * @return A value between 0 and 255.
+ */
+ public int getAlpha() {
+ return mState.mUseColor >>> 24;
+ }
+
+ /**
+ * Sets the color's alpha value.
+ *
+ * @param alpha The alpha value to set, between 0 and 255.
+ */
+ public void setAlpha(int alpha) {
+ alpha += alpha >> 7; // make it 0..256
+ int baseAlpha = mState.mBaseColor >>> 24;
+ int useAlpha = baseAlpha * alpha >> 8;
+ mState.mUseColor = (mState.mBaseColor << 8 >>> 8) | (useAlpha << 24);
+ }
+
+ /**
+ * Setting a color filter on a ColorDrawable has no effect.
+ *
+ * @param colorFilter Ignore.
+ */
+ public void setColorFilter(ColorFilter colorFilter) {
+ }
+
+ public int getOpacity() {
+ switch (mState.mUseColor >>> 24) {
+ case 255:
+ return PixelFormat.OPAQUE;
+ case 0:
+ return PixelFormat.TRANSPARENT;
+ }
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ColorDrawable);
+
+ int color = mState.mBaseColor;
+ color = a.getColor(com.android.internal.R.styleable.ColorDrawable_color, color);
+ mState.mBaseColor = mState.mUseColor = color;
+
+ a.recycle();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ mState.mChangingConfigurations = super.getChangingConfigurations();
+ return mState;
+ }
+
+ final static class ColorState extends ConstantState {
+ int mBaseColor; // initial color. never changes
+ int mUseColor; // basecolor modulated by setAlpha()
+ int mChangingConfigurations;
+
+ ColorState(ColorState state) {
+ if (state != null) {
+ mBaseColor = state.mBaseColor;
+ mUseColor = state.mUseColor;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new ColorDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
new file mode 100644
index 0000000..0021241
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -0,0 +1,768 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.*;
+import android.util.AttributeSet;
+import android.util.StateSet;
+import android.util.Xml;
+
+/**
+ * A Drawable is a general abstraction for "something that can be drawn." Most
+ * often you will deal with Drawable as the type of resource retrieved for
+ * drawing things to the screen; the Drawable class provides a generic API for
+ * dealing with an underlying visual resource that may take a variety of forms.
+ * Unlike a {@link android.view.View}, a Drawable does not have any facility to
+ * receive events or otherwise interact with the user.
+ *
+ * <p>In addition to simple drawing, Drawable provides a number of generic
+ * mechanisms for its client to interact with what is being drawn:
+ *
+ * <ul>
+ * <li> The {@link #setBounds} method <var>must</var> be called to tell the
+ * Drawable where it is drawn and how large it should be. All Drawables
+ * should respect the requested size, often simply by scaling their
+ * imagery. A client can find the preferred size for some Drawables with
+ * the {@link #getIntrinsicHeight} and {@link #getIntrinsicWidth} methods.
+ *
+ * <li> The {@link #getPadding} method can return from some Drawables
+ * information about how to frame content that is placed inside of them.
+ * For example, a Drawable that is intended to be the frame for a button
+ * widget would need to return padding that correctly places the label
+ * inside of itself.
+ *
+ * <li> The {@link #setState} method allows the client to tell the Drawable
+ * in which state it is to be drawn, such as "focused", "selected", etc.
+ * Some drawables may modify their imagery based on the selected state.
+ *
+ * <li> The {@link #setLevel} method allows the client to supply a single
+ * continuous controller that can modify the Drawable is displayed, such as
+ * a battery level or progress level. Some drawables may modify their
+ * imagery based on the current level.
+ *
+ * <li> A Drawable can perform animations by calling back to its client
+ * through the {@link Callback} interface. All clients should support this
+ * interface (via {@link #setCallback}) so that animations will work. A
+ * simple way to do this is through the system facilities such as
+ * {@link android.view.View#setBackgroundDrawable(Drawable)} and
+ * {@link android.widget.ImageView}.
+ * </ul>
+ *
+ * Though usually not visible to the application, Drawables may take a variety
+ * of forms:
+ *
+ * <ul>
+ * <li> <b>Bitmap</b>: the simplest Drawable, a PNG or JPEG image.
+ * <li> <b>Nine Patch</b>: an extension to the PNG format allows it to
+ * specify information about how to stretch it and place things inside of
+ * it.
+ * <li> <b>Shape</b>: contains simple drawing commands instead of a raw
+ * bitmap, allowing it to resize better in some cases.
+ * <li> <b>Layers</b>: a compound drawable, which draws multiple underlying
+ * drawables on top of each other.
+ * <li> <b>States</b>: a compound drawable that selects one of a set of
+ * drawables based on its state.
+ * <li> <b>Levels</b>: a compound drawable that selects one of a set of
+ * drawables based on its level.
+ * <li> <b>Scale</b>: a compound drawable with a single child drawable,
+ * whose overall size is modified based on the current level.
+ * </ul>
+ * <p>For information and examples of creating drawable resources (XML or bitmap files that
+ * can be loaded in code), see <a href="{@docRoot}devel/resources-i18n.html">Resources
+ * and Internationalization</a>.
+ */
+public abstract class Drawable {
+
+ private int[] mStateSet = StateSet.WILD_CARD;
+ private int mLevel = 0;
+ private int mChangingConfigurations = 0;
+ private Rect mBounds = new Rect();
+ /*package*/ Callback mCallback = null;
+ private boolean mVisible = true;
+
+ /**
+ * Draw in its bounds (set via setBounds) respecting optional effects such
+ * as alpha (set via setAlpha) and color filter (set via setColorFilter).
+ *
+ * @param canvas The canvas to draw into
+ */
+ public abstract void draw(Canvas canvas);
+
+ /**
+ * Specify a bounding rectangle for the Drawable. This is where the drawable
+ * will draw when its draw() method is called.
+ */
+ public void setBounds(int left, int top, int right, int bottom) {
+ Rect oldBounds = mBounds;
+
+ if (oldBounds.left != left || oldBounds.top != top ||
+ oldBounds.right != right || oldBounds.bottom != bottom) {
+ mBounds.set(left, top, right, bottom);
+ onBoundsChange(mBounds);
+ }
+ }
+
+ /**
+ * Specify a bounding rectangle for the Drawable. This is where the drawable
+ * will draw when its draw() method is called.
+ */
+ public void setBounds(Rect bounds) {
+ setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ }
+
+ /**
+ * Return a copy of the drawable's bounds in the specified Rect (allocated
+ * by the caller). The bounds specify where this will draw when its draw()
+ * method is called.
+ *
+ * @param bounds Rect to receive the drawable's bounds (allocated by the
+ * caller).
+ */
+ public final void copyBounds(Rect bounds) {
+ bounds.set(mBounds);
+ }
+
+ /**
+ * Return a copy of the drawable's bounds in a new Rect. This returns the
+ * same values as getBounds(), but the returned object is guaranteed to not
+ * be changed later by the drawable (i.e. it retains no reference to this
+ * rect). If the caller already has a Rect allocated, call copyBounds(rect)
+ *
+ * @return A copy of the drawable's bounds
+ */
+ public final Rect copyBounds() {
+ return new Rect(mBounds);
+ }
+
+ /**
+ * Return the drawable's bounds Rect. Note: for efficiency, the returned
+ * object may be the same object stored in the drawable (though this is not
+ * guaranteed), so if a persistent copy of the bounds is needed, call
+ * copyBounds(rect) instead.
+ *
+ * @return The bounds of the drawable (which may change later, so caller
+ * beware).
+ */
+ public final Rect getBounds() {
+ return mBounds;
+ }
+
+ /**
+ * Set a mask of the configuration parameters for which this drawable
+ * may change, requiring that it be re-created.
+ *
+ * @param configs A mask of the changing configuration parameters, as
+ * defined by {@link android.content.res.Configuration}.
+ *
+ * @see android.content.res.Configuration
+ */
+ public void setChangingConfigurations(int configs) {
+ mChangingConfigurations = configs;
+ }
+
+ /**
+ * Return a mask of the configuration parameters for which this drawable
+ * mau change, requiring that it be re-created. The default implementation
+ * returns whatever was provided through
+ * {@link #setChangingConfigurations(int)} or 0 by default. Subclasses
+ * may extend this to or in the changing configurations of any other
+ * drawables they hold.
+ *
+ * @return Returns a mask of the changing configuration parameters, as
+ * defined by {@link android.content.res.Configuration}.
+ *
+ * @see android.content.res.Configuration
+ */
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ /**
+ * Set to true to have the drawable dither its colors when drawn to a device
+ * with fewer than 8-bits per color component. This can improve the look on
+ * those devices, but can also slow down the drawing a little.
+ */
+ public void setDither(boolean dither) {}
+
+ /**
+ * Set to true to have the drawable filter its bitmap when scaled or rotated
+ * (for drawables that use bitmaps). If the drawable does not use bitmaps,
+ * this call is ignored. This can improve the look when scaled or rotated,
+ * but also slows down the drawing.
+ */
+ public void setFilterBitmap(boolean filter) {}
+
+ /**
+ * Implement this interface if you want to create an animated drawable that
+ * extends {@link android.graphics.drawable.Drawable Drawable}.
+ * Upon retrieving a drawable, use
+ * {@link Drawable#setCallback(android.graphics.drawable.Drawable.Callback)}
+ * to supply your implementation of the interface to the drawable; it uses
+ * this interface to schedule and execute animation changes.
+ */
+ public static interface Callback {
+ /**
+ * Called when the drawable needs to be redrawn. A view at this point
+ * should invalidate itself (or at least the part of itself where the
+ * drawable appears).
+ *
+ * @param who The drawable that is requesting the update.
+ */
+ public void invalidateDrawable(Drawable who);
+
+ /**
+ * A Drawable can call this to schedule the next frame of its
+ * animation. An implementation can generally simply call
+ * {@link android.os.Handler#postAtTime(Runnable, Object, long)} with
+ * the parameters <var>(what, who, when)</var> to perform the
+ * scheduling.
+ *
+ * @param who The drawable being scheduled.
+ * @param what The action to execute.
+ * @param when The time (in milliseconds) to run. The timebase is
+ * {@link android.os.SystemClock#uptimeMillis}
+ */
+ public void scheduleDrawable(Drawable who, Runnable what, long when);
+
+ /**
+ * A Drawable can call this to unschedule an action previously
+ * scheduled with {@link #scheduleDrawable}. An implementation can
+ * generally simply call
+ * {@link android.os.Handler#removeCallbacks(Runnable, Object)} with
+ * the parameters <var>(what, who)</var> to unschedule the drawable.
+ *
+ * @param who The drawable being unscheduled.
+ * @param what The action being unscheduled.
+ */
+ public void unscheduleDrawable(Drawable who, Runnable what);
+ }
+
+ /**
+ * Bind a {@link Callback} object to this Drawable. Required for clients
+ * that want to support animated drawables.
+ *
+ * @param cb The client's Callback implementation.
+ */
+ public final void setCallback(Callback cb) {
+ mCallback = cb;
+ }
+
+ /**
+ * Use the current {@link Callback} implementation to have this Drawable
+ * redrawn. Does nothing if there is no Callback attached to the
+ * Drawable.
+ *
+ * @see Callback#invalidateDrawable
+ */
+ public void invalidateSelf()
+ {
+ if (mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ /**
+ * Use the current {@link Callback} implementation to have this Drawable
+ * scheduled. Does nothing if there is no Callback attached to the
+ * Drawable.
+ *
+ * @param what The action being scheduled.
+ * @param when The time (in milliseconds) to run.
+ *
+ * @see Callback#scheduleDrawable
+ */
+ public void scheduleSelf(Runnable what, long when)
+ {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ /**
+ * Use the current {@link Callback} implementation to have this Drawable
+ * unscheduled. Does nothing if there is no Callback attached to the
+ * Drawable.
+ *
+ * @param what The runnable that you no longer want called.
+ *
+ * @see Callback#unscheduleDrawable
+ */
+ public void unscheduleSelf(Runnable what)
+ {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ /**
+ * Specify an alpha value for the drawable. 0 means fully transparent, and
+ * 255 means fully opaque.
+ */
+ public abstract void setAlpha(int alpha);
+
+ /**
+ * Specify an optional colorFilter for the drawable. Pass null to remove
+ * any filters.
+ */
+ public abstract void setColorFilter(ColorFilter cf);
+
+ /**
+ * Specify a color and porterduff mode to be the colorfilter for this
+ * drawable.
+ */
+ public void setColorFilter(int color, PorterDuff.Mode mode) {
+ setColorFilter(new PorterDuffColorFilter(color, mode));
+ }
+
+ public void clearColorFilter() {
+ setColorFilter(null);
+ }
+
+ /**
+ * Indicates whether this view will change its appearance based on state.
+ * Clients can use this to determine whether it is necessary to calculate
+ * their state and call setState.
+ *
+ * @return True if this view changes its appearance based on state, false
+ * otherwise.
+ *
+ * @see #setState(int[])
+ */
+ public boolean isStateful() {
+ return false;
+ }
+
+ /**
+ * Specify a set of states for the drawable. These are use-case specific,
+ * so see the relevant documentation. As an example, the background for
+ * widgets like Button understand the following states:
+ * [{@link android.R.attr#state_focused},
+ * {@link android.R.attr#state_pressed}].
+ *
+ * <p>If the new state you are supplying causes the appearance of the
+ * Drawable to change, then it is responsible for calling
+ * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
+ * true will be returned from this function.
+ *
+ * <p>Note: The Drawable holds a reference on to <var>stateSet</var>
+ * until a new state array is given to it, so you must not modify this
+ * array during that time.</p>
+ *
+ * @param stateSet The new set of states to be displayed.
+ *
+ * @return Returns true if this change in state has caused the appearance
+ * of the Drawable to change (hence requiring an invalidate), otherwise
+ * returns false.
+ */
+ public boolean setState(final int[] stateSet) {
+ if (!Arrays.equals(mStateSet, stateSet)) {
+ mStateSet = stateSet;
+ return onStateChange(stateSet);
+ }
+ return false;
+ }
+
+ /**
+ * Describes the current state, as a union of primitve states, such as
+ * {@link android.R.attr#state_focused},
+ * {@link android.R.attr#state_selected}, etc.
+ * Some drawables may modify their imagery based on the selected state.
+ * @return An array of resource Ids describing the current state.
+ */
+ public int[] getState() {
+ return mStateSet;
+ }
+
+ /**
+ * @return The current drawable that will be used by this drawable. For simple drawables, this
+ * is just the drawable itself. For drawables that change state like
+ * {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
+ * currently in use.
+ */
+ public Drawable getCurrent() {
+ return this;
+ }
+
+ /**
+ * Specify the level for the drawable. This allows a drawable to vary its
+ * imagery based on a continuous controller, for example to show progress
+ * or volume level.
+ *
+ * <p>If the new level you are supplying causes the appearance of the
+ * Drawable to change, then it is responsible for calling
+ * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
+ * true will be returned from this function.
+ *
+ * @param level The new level, from 0 (minimum) to 10000 (maximum).
+ *
+ * @return Returns true if this change in level has caused the appearance
+ * of the Drawable to change (hence requiring an invalidate), otherwise
+ * returns false.
+ */
+ public final boolean setLevel(int level) {
+ if (mLevel != level) {
+ mLevel = level;
+ return onLevelChange(level);
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the current level.
+ *
+ * @return int Current level, from 0 (minimum) to 10000 (maximum).
+ */
+ public final int getLevel() {
+ return mLevel;
+ }
+
+ /**
+ * Set whether this Drawable is visible. This generally does not impact
+ * the Drawable's behavior, but is a hint that can be used by some
+ * Drawables, for example, to decide whether run animations.
+ *
+ * @param visible Set to true if visible, false if not.
+ * @param restart You can supply true here to force the drawable to behave
+ * as if it has just become visible, even if it had last
+ * been set visible. Used for example to force animations
+ * to restart.
+ *
+ * @return boolean Returns true if the new visibility is different than
+ * its previous state.
+ */
+ public boolean setVisible(boolean visible, boolean restart) {
+ boolean changed = mVisible != visible;
+ mVisible = visible;
+ return changed;
+ }
+
+ public final boolean isVisible() {
+ return mVisible;
+ }
+
+ /**
+ * Return the opacity/transparency of this Drawable. The returned value is
+ * one of the abstract format constants in
+ * {@link android.graphics.PixelFormat}:
+ * {@link android.graphics.PixelFormat#UNKNOWN},
+ * {@link android.graphics.PixelFormat#TRANSLUCENT},
+ * {@link android.graphics.PixelFormat#TRANSPARENT}, or
+ * {@link android.graphics.PixelFormat#OPAQUE}.
+ *
+ * <p>Generally a Drawable should be as conservative as possible with the
+ * value it returns. For example, if it contains multiple child drawables
+ * and only shows one of them at a time, if only one of the children is
+ * TRANSLUCENT and the others are OPAQUE then TRANSLUCENT should be
+ * returned. You can use the method {@link #resolveOpacity} to perform a
+ * standard reduction of two opacities to the appropriate single output.
+ *
+ * <p>Note that the returned value does <em>not</em> take into account a
+ * custom alpha or color filter that has been applied by the client through
+ * the {@link #setAlpha} or {@link #setColorFilter} methods.
+ *
+ * @return int The opacity class of the Drawable.
+ *
+ * @see android.graphics.PixelFormat
+ */
+ public abstract int getOpacity();
+
+ /**
+ * Return the appropriate opacity value for two source opacities. If
+ * either is UNKNOWN, that is returned; else, if either is TRANSLUCENT,
+ * that is returned; else, if either is TRANSPARENT, that is returned;
+ * else, OPAQUE is returned.
+ *
+ * <p>This is to help in implementing {@link #getOpacity}.
+ *
+ * @param op1 One opacity value.
+ * @param op2 Another opacity value.
+ *
+ * @return int The combined opacity value.
+ *
+ * @see #getOpacity
+ */
+ public static int resolveOpacity(int op1, int op2) {
+ if (op1 == op2) {
+ return op1;
+ }
+ if (op1 == PixelFormat.UNKNOWN || op2 == PixelFormat.UNKNOWN) {
+ return PixelFormat.UNKNOWN;
+ }
+ if (op1 == PixelFormat.TRANSLUCENT || op2 == PixelFormat.TRANSLUCENT) {
+ return PixelFormat.TRANSLUCENT;
+ }
+ if (op1 == PixelFormat.TRANSPARENT || op2 == PixelFormat.TRANSPARENT) {
+ return PixelFormat.TRANSPARENT;
+ }
+ return PixelFormat.OPAQUE;
+ }
+
+ /**
+ * Returns a Region representing the part of the Drawable that is completely
+ * transparent. This can be used to perform drawing operations, identifying
+ * which parts of the target will not change when rendering the Drawable.
+ * The default implementation returns null, indicating no transparent
+ * region; subclasses can optionally override this to return an actual
+ * Region if they want to supply this optimization information, but it is
+ * not required that they do so.
+ *
+ * @return Returns null if the Drawables has no transparent region to
+ * report, else a Region holding the parts of the Drawable's bounds that
+ * are transparent.
+ */
+ public Region getTransparentRegion() {
+ return null;
+ }
+
+ /**
+ * Override this in your subclass to change appearance if you recognize the
+ * specified state.
+ *
+ * @return Returns true if the state change has caused the appearance of
+ * the Drawable to change (that is, it needs to be drawn), else false
+ * if it looks the same and there is no need to redraw it since its
+ * last state.
+ */
+ protected boolean onStateChange(int[] state) { return false; }
+ /** Override this in your subclass to change appearance if you vary based
+ * on level.
+ * @return Returns true if the level change has caused the appearance of
+ * the Drawable to change (that is, it needs to be drawn), else false
+ * if it looks the same and there is no need to redraw it since its
+ * last level.
+ */
+ protected boolean onLevelChange(int level) { return false; }
+ /**
+ * Override this in your subclass to change appearance if you recognize the
+ * specified state.
+ */
+ protected void onBoundsChange(Rect bounds) {}
+
+ /**
+ * Return the intrinsic width of the underlying drawable object. Returns
+ * -1 if it has no intrinsic width, such as with a solid color.
+ */
+ public int getIntrinsicWidth() {
+ return -1;
+ }
+
+ /**
+ * Return the intrinsic height of the underlying drawable object. Returns
+ * -1 if it has no intrinsic height, such as with a solid color.
+ */
+ public int getIntrinsicHeight() {
+ return -1;
+ }
+
+ /**
+ * Returns the minimum width suggested by this Drawable. If a View uses this
+ * Drawable as a background, it is suggested that the View use at least this
+ * value for its width. (There will be some scenarios where this will not be
+ * possible.) This value should INCLUDE any padding.
+ *
+ * @return The minimum width suggested by this Drawable. If this Drawable
+ * doesn't have a suggested minimum width, 0 is returned.
+ */
+ public int getMinimumWidth() {
+ final int intrinsicWidth = getIntrinsicWidth();
+ return intrinsicWidth > 0 ? intrinsicWidth : 0;
+ }
+
+ /**
+ * Returns the minimum height suggested by this Drawable. If a View uses this
+ * Drawable as a background, it is suggested that the View use at least this
+ * value for its height. (There will be some scenarios where this will not be
+ * possible.) This value should INCLUDE any padding.
+ *
+ * @return The minimum height suggested by this Drawable. If this Drawable
+ * doesn't have a suggested minimum height, 0 is returned.
+ */
+ public int getMinimumHeight() {
+ final int intrinsicHeight = getIntrinsicHeight();
+ return intrinsicHeight > 0 ? intrinsicHeight : 0;
+ }
+
+ /**
+ * 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.
+ */
+ public boolean getPadding(Rect padding) {
+ padding.set(0, 0, 0, 0);
+ return false;
+ }
+
+ /**
+ * Create a drawable from an inputstream
+ */
+ public static Drawable createFromStream(InputStream is, String srcName) {
+ if (is == null) {
+ return null;
+ }
+
+ /* ugh. The decodeStream contract is that we have already allocated
+ the pad rect, but if the bitmap does not had a ninepatch chunk,
+ then the pad will be ignored. If we could change this to lazily
+ alloc/assign the rect, we could avoid the GC churn of making new
+ Rects only to drop them on the floor.
+ */
+ Rect pad = new Rect();
+ Bitmap bm = BitmapFactory.decodeStream(is, pad, null);
+ if (bm != null) {
+ byte[] np = bm.getNinePatchChunk();
+ if (np == null || !NinePatch.isNinePatchChunk(np)) {
+ np = null;
+ pad = null;
+ }
+ return drawableFromBitmap(bm, np, pad, srcName);
+ }
+ return null;
+ }
+
+ /**
+ * Create a drawable from an XML document. For more information on how to
+ * create resources in XML, see
+ * <a href="{@docRoot}devel/resources-i18n.html">Resources and
+ * Internationalization</a>.
+ */
+ public static Drawable createFromXml(Resources r, XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ Drawable drawable = createFromXmlInner(r, parser, attrs);
+
+ if (drawable == null) {
+ throw new RuntimeException("Unknown initial tag: " + parser.getName());
+ }
+
+ return drawable;
+ }
+
+ /**
+ * Create from inside an XML document. Called on a parser positioned at
+ * a tag in an XML document, tries to create a Drawable from that tag.
+ * Returns null if the tag is not a valid drawable.
+ */
+ public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ Drawable drawable;
+
+ final String name = parser.getName();
+
+ if (name.equals("selector")) {
+ drawable = new StateListDrawable();
+ } else if (name.equals("level-list")) {
+ drawable = new LevelListDrawable();
+ } else if (name.equals("layer-list")) {
+ drawable = new LayerDrawable();
+ } else if (name.equals("transition")) {
+ drawable = new TransitionDrawable();
+ } else if (name.equals("color")) {
+ drawable = new ColorDrawable();
+ } else if (name.equals("shape")) {
+ drawable = new GradientDrawable();
+ } else if (name.equals("scale")) {
+ drawable = new ScaleDrawable();
+ } else if (name.equals("clip")) {
+ drawable = new ClipDrawable();
+ } else if (name.equals("rotate")) {
+ drawable = new RotateDrawable();
+ } else if (name.equals("animation-list")) {
+ drawable = new AnimationDrawable();
+ } else if (name.equals("inset")) {
+ drawable = new InsetDrawable();
+ } else if (name.equals("bitmap")) {
+ drawable = new BitmapDrawable();
+ } else {
+ throw new XmlPullParserException(parser.getPositionDescription() +
+ ": invalid drawable tag " + name);
+ }
+
+ drawable.inflate(r, parser, attrs);
+ return drawable;
+ }
+
+
+ /**
+ * Create a drawable from file path name.
+ */
+ public static Drawable createFromPath(String pathName) {
+ if (pathName == null) {
+ return null;
+ }
+
+ Bitmap bm = BitmapFactory.decodeFile(pathName);
+ if (bm != null) {
+ return drawableFromBitmap(bm, null, null, pathName);
+ }
+
+ return null;
+ }
+
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable);
+ inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible);
+ a.recycle();
+ }
+
+ void inflateWithAttributes(Resources r, XmlPullParser parser,
+ TypedArray attrs, int visibleAttr)
+ throws XmlPullParserException, IOException {
+
+ mVisible = attrs.getBoolean(visibleAttr, mVisible);
+ }
+
+ public static abstract class ConstantState {
+ public abstract Drawable newDrawable();
+ public abstract int getChangingConfigurations();
+ }
+
+ public ConstantState getConstantState() {
+ return null;
+ }
+
+ private static Drawable drawableFromBitmap(Bitmap bm, byte[] np, Rect pad, String srcName) {
+ if (np != null) {
+ return new NinePatchDrawable(bm, np, pad, srcName);
+ }
+ return new BitmapDrawable(bm);
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
new file mode 100644
index 0000000..e6c48be
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import android.graphics.*;
+
+public class DrawableContainer extends Drawable implements Drawable.Callback {
+
+ private DrawableContainerState mDrawableContainerState;
+ private Drawable mCurrDrawable;
+ private int mAlpha = 0xFF;
+ private ColorFilter mColorFilter;
+ private boolean mDither;
+
+ private int mCurIndex = -1;
+
+ // overrides from Drawable
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mCurrDrawable != null) {
+ mCurrDrawable.draw(canvas);
+ }
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mDrawableContainerState.mChangingConfigurations
+ | mDrawableContainerState.mChildrenChangingConfigurations;
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ final Rect r = mDrawableContainerState.getConstantPadding();
+ if (r != null) {
+ padding.set(r);
+ return true;
+ }
+ if (mCurrDrawable != null) {
+ return mCurrDrawable.getPadding(padding);
+ } else {
+ return super.getPadding(padding);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ if (mAlpha != alpha) {
+ mAlpha = alpha;
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setAlpha(alpha);
+ }
+ }
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ if (mDither != dither) {
+ mDither = dither;
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setDither(mDither);
+ }
+ }
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ if (mColorFilter != cf) {
+ mColorFilter = cf;
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setColorFilter(cf);
+ }
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setBounds(bounds);
+ }
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mDrawableContainerState.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ if (mCurrDrawable != null) {
+ return mCurrDrawable.setState(state);
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ if (mCurrDrawable != null) {
+ return mCurrDrawable.setLevel(level);
+ }
+ return false;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ if (mDrawableContainerState.isConstantSize()) {
+ return mDrawableContainerState.getConstantWidth();
+ }
+ return mCurrDrawable != null ? mCurrDrawable.getIntrinsicWidth() : -1;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ if (mDrawableContainerState.isConstantSize()) {
+ return mDrawableContainerState.getConstantHeight();
+ }
+ return mCurrDrawable != null ? mCurrDrawable.getIntrinsicHeight() : -1;
+ }
+
+ @Override
+ public int getMinimumWidth() {
+ if (mDrawableContainerState.isConstantSize()) {
+ return mDrawableContainerState.getConstantMinimumWidth();
+ }
+ return mCurrDrawable != null ? mCurrDrawable.getMinimumWidth() : 0;
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ if (mDrawableContainerState.isConstantSize()) {
+ return mDrawableContainerState.getConstantMinimumHeight();
+ }
+ return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0;
+ }
+
+ public void invalidateDrawable(Drawable who)
+ {
+ if (who == mCurrDrawable && mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ public void scheduleDrawable(Drawable who, Runnable what, long when)
+ {
+ if (who == mCurrDrawable && mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ public void unscheduleDrawable(Drawable who, Runnable what)
+ {
+ if (who == mCurrDrawable && mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ boolean changed = super.setVisible(visible, restart);
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setVisible(visible, restart);
+ }
+ return changed;
+ }
+
+ @Override
+ public int getOpacity() {
+ return mDrawableContainerState.getOpacity();
+ }
+
+ public boolean selectDrawable(int idx)
+ {
+ if (idx == mCurIndex) {
+ return false;
+ }
+ if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
+ Drawable d = mDrawableContainerState.mDrawables[idx];
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setVisible(false, false);
+ }
+ mCurrDrawable = d;
+ mCurIndex = idx;
+ if (d != null) {
+ d.setVisible(isVisible(), true);
+ d.setAlpha(mAlpha);
+ d.setDither(mDither);
+ d.setColorFilter(mColorFilter);
+ d.setState(getState());
+ d.setLevel(getLevel());
+ d.setBounds(getBounds());
+ }
+ } else {
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setVisible(false, false);
+ }
+ mCurrDrawable = null;
+ mCurIndex = -1;
+ }
+ invalidateSelf();
+ return true;
+ }
+
+ @Override
+ public Drawable getCurrent() {
+ return mCurrDrawable;
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mDrawableContainerState.canConstantState()) {
+ mDrawableContainerState.mChangingConfigurations = super.getChangingConfigurations();
+ return mDrawableContainerState;
+ }
+ return null;
+ }
+
+ public abstract static class DrawableContainerState extends ConstantState {
+ final DrawableContainer mOwner;
+
+ int mChangingConfigurations;
+ int mChildrenChangingConfigurations;
+
+ Drawable[] mDrawables;
+ int mNumChildren;
+
+ boolean mVariablePadding = false;
+ Rect mConstantPadding = null;
+
+ boolean mConstantSize = false;
+ boolean mComputedConstantSize = false;
+ int mConstantWidth;
+ int mConstantHeight;
+ int mConstantMinimumWidth;
+ int mConstantMinimumHeight;
+
+ boolean mHaveOpacity = false;
+ int mOpacity;
+
+ boolean mHaveStateful = false;
+ boolean mStateful;
+
+ boolean mCheckedConstantState;
+ boolean mCanConstantState;
+
+ DrawableContainerState(DrawableContainerState orig, DrawableContainer owner) {
+ mOwner = owner;
+
+ if (orig != null) {
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations;
+
+ final Drawable[] origDr = orig.mDrawables;
+
+ mDrawables = new Drawable[origDr.length];
+ mNumChildren = orig.mNumChildren;
+
+ final int N = mNumChildren;
+ for (int i=0; i<N; i++) {
+ mDrawables[i] = origDr[i].getConstantState().newDrawable();
+ mDrawables[i].setCallback(owner);
+ }
+
+ mCheckedConstantState = mCanConstantState = true;
+ mVariablePadding = orig.mVariablePadding;
+ mConstantPadding = orig.mConstantPadding;
+ mConstantSize = orig.mConstantSize;
+ mComputedConstantSize = orig.mComputedConstantSize;
+ mConstantWidth = orig.mConstantWidth;
+ mConstantHeight = orig.mConstantHeight;
+
+ mHaveOpacity = orig.mHaveOpacity;
+ mOpacity = orig.mOpacity;
+ mHaveStateful = orig.mHaveStateful;
+ mStateful = orig.mStateful;
+
+ } else {
+ mDrawables = new Drawable[10];
+ mNumChildren = 0;
+ mCheckedConstantState = mCanConstantState = false;
+ }
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ public final int addChild(Drawable dr) {
+ final int pos = mNumChildren;
+
+ if (pos >= mDrawables.length) {
+ growArray(pos, pos+10);
+ }
+
+ dr.setVisible(false, true);
+ dr.setCallback(mOwner);
+
+ mDrawables[pos] = dr;
+ mNumChildren++;
+ mChildrenChangingConfigurations |= dr.getChangingConfigurations();
+ mHaveOpacity = false;
+ mHaveStateful = false;
+
+ mConstantPadding = null;
+ mComputedConstantSize = false;
+
+ return pos;
+ }
+
+ public final int getChildCount()
+ {
+ return mNumChildren;
+ }
+
+ public final Drawable[] getChildren()
+ {
+ return mDrawables;
+ }
+
+ /** A boolean value indicating whether to use the maximum padding value of
+ * all frames in the set (false), or to use the padding value of the frame
+ * being shown (true). Default value is false.
+ */
+ public final void setVariablePadding(boolean variable)
+ {
+ mVariablePadding = variable;
+ }
+
+ public final Rect getConstantPadding()
+ {
+ if (mVariablePadding) {
+ return null;
+ }
+ if (mConstantPadding != null) {
+ return mConstantPadding;
+ }
+
+ Rect r = new Rect(0, 0, 0, 0);
+ Rect t = new Rect();
+ final int N = getChildCount();
+ for (int i=0; i<N; i++) {
+ if (mDrawables[i].getPadding(t)) {
+ if (t.left > r.left) r.left = t.left;
+ if (t.top > r.top) r.top = t.top;
+ if (t.right > r.right) r.right = t.right;
+ if (t.bottom > r.bottom) r.bottom = t.bottom;
+ }
+ }
+ return (mConstantPadding=r);
+ }
+
+ public final void setConstantSize(boolean constant)
+ {
+ mConstantSize = constant;
+ }
+
+ public final boolean isConstantSize()
+ {
+ return mConstantSize;
+ }
+
+ public final int getConstantWidth()
+ {
+ if (!mComputedConstantSize) {
+ computeConstantSize();
+ }
+
+ return mConstantWidth;
+ }
+
+ public final int getConstantHeight()
+ {
+ if (!mComputedConstantSize) {
+ computeConstantSize();
+ }
+
+ return mConstantHeight;
+ }
+
+ public final int getConstantMinimumWidth()
+ {
+ if (!mComputedConstantSize) {
+ computeConstantSize();
+ }
+
+ return mConstantMinimumWidth;
+ }
+
+ public final int getConstantMinimumHeight()
+ {
+ if (!mComputedConstantSize) {
+ computeConstantSize();
+ }
+
+ return mConstantMinimumHeight;
+ }
+
+ private void computeConstantSize()
+ {
+ mComputedConstantSize = true;
+
+ final int N = getChildCount();
+ mConstantWidth = mConstantHeight = 0;
+ mConstantMinimumWidth = mConstantMinimumHeight = 0;
+ for (int i=0; i<N; i++) {
+ Drawable dr = mDrawables[i];
+ int s = dr.getIntrinsicWidth();
+ if (s > mConstantWidth) mConstantWidth = s;
+ s = dr.getIntrinsicHeight();
+ if (s > mConstantHeight) mConstantHeight = s;
+ s = dr.getMinimumWidth();
+ if (s > mConstantMinimumWidth) mConstantMinimumWidth = s;
+ s = dr.getMinimumHeight();
+ if (s > mConstantMinimumHeight) mConstantMinimumHeight = s;
+ }
+ }
+
+ public final int getOpacity()
+ {
+ if (mHaveOpacity) {
+ return mOpacity;
+ }
+
+ final int N = getChildCount();
+ int op = N > 0
+ ? mDrawables[0].getOpacity() : PixelFormat.TRANSPARENT;
+ for (int i=1; i<N; i++) {
+ op = Drawable.resolveOpacity(op, mDrawables[i].getOpacity());
+ }
+ mOpacity = op;
+ mHaveOpacity = true;
+ return op;
+ }
+
+ public final boolean isStateful() {
+ if (mHaveStateful) {
+ return mStateful;
+ }
+
+ boolean stateful = false;
+ final int N = getChildCount();
+ for (int i = 0; i < N; i++) {
+ if (mDrawables[i].isStateful()) {
+ stateful = true;
+ break;
+ }
+ }
+
+ mStateful = stateful;
+ mHaveStateful = true;
+ return stateful;
+ }
+
+ public void growArray(int oldSize, int newSize)
+ {
+ Drawable[] newDrawables = new Drawable[newSize];
+ System.arraycopy(mDrawables, 0, newDrawables, 0, oldSize);
+ mDrawables = newDrawables;
+ }
+
+ public synchronized boolean canConstantState() {
+ if (!mCheckedConstantState) {
+ mCanConstantState = true;
+ final int N = mNumChildren;
+ for (int i=0; i<N; i++) {
+ if (mDrawables[i].getConstantState() == null) {
+ mCanConstantState = false;
+ break;
+ }
+ }
+ mCheckedConstantState = true;
+ }
+
+ return mCanConstantState;
+ }
+ }
+
+ protected void setConstantState(DrawableContainerState state)
+ {
+ mDrawableContainerState = state;
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
new file mode 100644
index 0000000..ab3b23d
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -0,0 +1,891 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.DashPathEffect;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.Path;
+import android.graphics.RadialGradient;
+import android.graphics.SweepGradient;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * A simple color gradient for buttons, backgrounds, etc. See
+ * <a href="{@docRoot}reference/available-resources.html#gradientdrawable">Gradient</a>
+ * in the Resources topic to learn how to specify this type as an XML resource.
+ */
+public class GradientDrawable extends Drawable {
+ /**
+ * Shape is a rectangle, possibly with rounded corners
+ */
+ public static final int RECTANGLE = 0;
+
+ /**
+ * Shape is an ellipse
+ */
+ public static final int OVAL = 1;
+
+ /**
+ * Shape is a line
+ */
+ public static final int LINE = 2;
+
+ /**
+ * Shape is a ring.
+ */
+ public static final int RING = 3;
+
+ /**
+ * Gradient is linear (default.)
+ */
+ public static final int LINEAR_GRADIENT = 0;
+
+ /**
+ * Gradient is circular.
+ */
+ public static final int RADIAL_GRADIENT = 1;
+
+ /**
+ * Gradient is a sweep.
+ */
+ public static final int SWEEP_GRADIENT = 2;
+
+ private final GradientState mGradientState;
+
+ private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private Rect mPadding;
+ private Paint mStrokePaint; // optional, set by the caller
+ private ColorFilter mColorFilter; // optional, set by the caller
+ private int mAlpha = 0xFF; // modified by the caller
+ private boolean mDither;
+
+ private final Path mPath = new Path();
+ private final RectF mRect = new RectF();
+
+ private Paint mLayerPaint; // internal, used if we use saveLayer()
+ private boolean mRectIsDirty; // internal state
+
+ /**
+ * Controls how the gradient is oriented relative to the drawable's bounds
+ */
+ public enum Orientation {
+ /** draw the gradient from the top to the bottom */
+ TOP_BOTTOM,
+ /** draw the gradient from the top-right to the bottom-left */
+ TR_BL,
+ /** draw the gradient from the right to the left */
+ RIGHT_LEFT,
+ /** draw the gradient from the bottom-right to the top-left */
+ BR_TL,
+ /** draw the gradient from the bottom to the top */
+ BOTTOM_TOP,
+ /** draw the gradient from the bottom-left to the top-right */
+ BL_TR,
+ /** draw the gradient from the left to the right */
+ LEFT_RIGHT,
+ /** draw the gradient from the top-left to the bottom-right */
+ TL_BR,
+ }
+
+ public GradientDrawable() {
+ this(new GradientState(Orientation.TOP_BOTTOM, null));
+ }
+
+ /**
+ * Create a new gradient drawable given an orientation and an array
+ * of colors for the gradient.
+ */
+ public GradientDrawable(Orientation orientation, int[] colors) {
+ this(new GradientState(orientation, colors));
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ if (mPadding != null) {
+ padding.set(mPadding);
+ return true;
+ } else {
+ return super.getPadding(padding);
+ }
+ }
+
+ /**
+ * Specify radii for each of the 4 corners. For each corner, the array
+ * contains 2 values, [X_radius, Y_radius]. The corners are ordered
+ * top-left, top-right, bottom-right, bottom-left
+ */
+ public void setCornerRadii(float[] radii) {
+ mGradientState.setCornerRadii(radii);
+ }
+
+ /**
+ * Specify radius for the corners of the gradient. If this is > 0, then the
+ * drawable is drawn in a round-rectangle, rather than a rectangle.
+ */
+ public void setCornerRadius(float radius) {
+ mGradientState.setCornerRadius(radius);
+ }
+
+ /**
+ * Set the stroke width and color for the drawable. If width is zero,
+ * then no stroke is drawn.
+ */
+ public void setStroke(int width, int color) {
+ setStroke(width, color, 0, 0);
+ }
+
+ public void setStroke(int width, int color, float dashWidth, float dashGap) {
+ mGradientState.setStroke(width, color, dashWidth, dashGap);
+
+ if (mStrokePaint == null) {
+ mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mStrokePaint.setStyle(Paint.Style.STROKE);
+ }
+ mStrokePaint.setStrokeWidth(width);
+ mStrokePaint.setColor(color);
+
+ DashPathEffect e = null;
+ if (dashWidth > 0) {
+ e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0);
+ }
+ mStrokePaint.setPathEffect(e);
+ }
+
+ public void setSize(int width, int height) {
+ mGradientState.setSize(width, height);
+ }
+
+ public void setShape(int shape) {
+ mGradientState.setShape(shape);
+ }
+
+ public void setGradientType(int gradient) {
+ mGradientState.setGradientType(gradient);
+ mRectIsDirty = true;
+ }
+
+ public void setGradientCenter(float x, float y) {
+ mGradientState.setGradientCenter(x, y);
+ }
+
+ public void setGradientRadius(float gradientRadius) {
+ mGradientState.setGradientRadius(gradientRadius);
+ }
+
+ public void setUseLevel(boolean useLevel) {
+ mGradientState.mUseLevel = useLevel;
+ }
+
+ private int modulateAlpha(int alpha) {
+ int scale = mAlpha + (mAlpha >> 7);
+ return alpha * scale >> 8;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (!ensureValidRect()) {
+ // nothing to draw
+ return;
+ }
+
+ // remember the alpha values, in case we temporarily overwrite them
+ // when we modulate them with mAlpha
+ final int prevFillAlpha = mFillPaint.getAlpha();
+ final int prevStrokeAlpha = mStrokePaint != null ?
+ mStrokePaint.getAlpha() : 0;
+ // compute the modulate alpha values
+ final int currFillAlpha = modulateAlpha(prevFillAlpha);
+ final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha);
+
+ final boolean haveStroke = currStrokeAlpha > 0 &&
+ mStrokePaint.getStrokeWidth() > 0;
+ final boolean haveFill = currFillAlpha > 0;
+ final GradientState st = mGradientState;
+ /* we need a layer iff we're drawing both a fill and stroke, and the
+ stroke is non-opaque, and our shapetype actually supports
+ fill+stroke. Otherwise we can just draw the stroke (if any) on top
+ of the fill (if any) without worrying about blending artifacts.
+ */
+ final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
+ currStrokeAlpha < 255;
+
+ /* Drawing with a layer is slower than direct drawing, but it
+ allows us to apply paint effects like alpha and colorfilter to
+ the result of multiple separate draws. In our case, if the user
+ asks for a non-opaque alpha value (via setAlpha), and we're
+ stroking, then we need to apply the alpha AFTER we've drawn
+ both the fill and the stroke.
+ */
+ if (useLayer) {
+ if (mLayerPaint == null) {
+ mLayerPaint = new Paint();
+ }
+ mLayerPaint.setDither(mDither);
+ mLayerPaint.setAlpha(mAlpha);
+ mLayerPaint.setColorFilter(mColorFilter);
+
+ float rad = mStrokePaint.getStrokeWidth();
+ canvas.saveLayer(mRect.left - rad, mRect.top - rad,
+ mRect.right + rad, mRect.bottom + rad,
+ mLayerPaint, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
+
+ // don't perform the filter in our individual paints
+ // since the layer will do it for us
+ mFillPaint.setColorFilter(null);
+ mStrokePaint.setColorFilter(null);
+ } else {
+ /* if we're not using a layer, apply the dither/filter to our
+ individual paints
+ */
+ mFillPaint.setAlpha(currFillAlpha);
+ mFillPaint.setDither(mDither);
+ mFillPaint.setColorFilter(mColorFilter);
+ if (haveStroke) {
+ mStrokePaint.setAlpha(currStrokeAlpha);
+ mStrokePaint.setDither(mDither);
+ mStrokePaint.setColorFilter(mColorFilter);
+ }
+ }
+
+ switch (st.mShape) {
+ case RECTANGLE:
+ if (st.mRadiusArray != null) {
+ mPath.reset();
+ mPath.addRoundRect(mRect, st.mRadiusArray,
+ Path.Direction.CW);
+ canvas.drawPath(mPath, mFillPaint);
+ if (haveStroke) {
+ canvas.drawPath(mPath, mStrokePaint);
+ }
+ }
+ else {
+ float rad = st.mRadius;
+ canvas.drawRoundRect(mRect, rad, rad, mFillPaint);
+ if (haveStroke) {
+ canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
+ }
+ }
+ break;
+ case OVAL:
+ canvas.drawOval(mRect, mFillPaint);
+ if (haveStroke) {
+ canvas.drawOval(mRect, mStrokePaint);
+ }
+ break;
+ case LINE: {
+ RectF r = mRect;
+ float y = r.centerY();
+ canvas.drawLine(r.left, y, r.right, y, mStrokePaint);
+ break;
+ }
+ case RING:
+ Path ring = buildRing(st);
+ canvas.drawPath(ring, mFillPaint);
+ if (haveStroke) {
+ canvas.drawPath(ring, mStrokePaint);
+ }
+ break;
+ }
+
+ if (useLayer) {
+ canvas.restore();
+ } else {
+ mFillPaint.setAlpha(prevFillAlpha);
+ if (haveStroke) {
+ mStrokePaint.setAlpha(prevStrokeAlpha);
+ }
+ }
+ }
+
+ private Path buildRing(GradientState st) {
+ float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
+
+ RectF bounds = new RectF(mRect);
+
+ float x = bounds.width() / 2.0f;
+ float y = bounds.height() / 2.0f;
+
+ float thickness = bounds.width() / st.mThickness;
+ // inner radius
+ float radius = bounds.width() / st.mInnerRadius;
+
+ RectF innerBounds = new RectF(bounds);
+ innerBounds.inset(x - radius, y - radius);
+
+ bounds = new RectF(innerBounds);
+ bounds.inset(-thickness, -thickness);
+
+ Path path = new Path();
+ // arcTo treats the sweep angle mod 360, so check for that, since we
+ // think 360 means draw the entire oval
+ if (sweep < 360 && sweep > -360) {
+ path.setFillType(Path.FillType.EVEN_ODD);
+ // inner top
+ path.moveTo(x + radius, y);
+ // outer top
+ path.lineTo(x + radius + thickness, y);
+ // outer arc
+ path.arcTo(bounds, 0.0f, sweep, false);
+ // inner arc
+ path.arcTo(innerBounds, sweep, -sweep, false);
+ path.close();
+ } else {
+ // add the entire ovals
+ path.addOval(bounds, Path.Direction.CW);
+ path.addOval(innerBounds, Path.Direction.CCW);
+ }
+
+ return path;
+ }
+
+ public void setColor(int argb) {
+ mGradientState.setSolidColor(argb);
+ mFillPaint.setColor(argb);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mGradientState.mChangingConfigurations;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mAlpha = alpha;
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ mDither = dither;
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mColorFilter = cf;
+ }
+
+ @Override
+ public int getOpacity() {
+ // XXX need to figure out the actual opacity...
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect r) {
+ super.onBoundsChange(r);
+ mRectIsDirty = true;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ super.onLevelChange(level);
+ mRectIsDirty = true;
+ invalidateSelf();
+ return true;
+ }
+
+ /**
+ * This checks mRectIsDirty, and if it is true, recomputes both our drawing
+ * rectangle (mRect) and the gradient itself, since it depends on our
+ * rectangle too.
+ * @return true if the resulting rectangle is not empty, false otherwise
+ */
+ private boolean ensureValidRect() {
+ if (mRectIsDirty) {
+ mRectIsDirty = false;
+
+ Rect bounds = getBounds();
+ float inset = 0;
+
+ if (mStrokePaint != null) {
+ inset = mStrokePaint.getStrokeWidth() * 0.5f;
+ }
+
+ final GradientState st = mGradientState;
+
+ mRect.set(bounds.left + inset, bounds.top + inset,
+ bounds.right - inset, bounds.bottom - inset);
+
+ if (st.mColors != null) {
+ RectF r = mRect;
+ float x0, x1, y0, y1;
+
+ if (st.mGradient == LINEAR_GRADIENT) {
+ final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;
+ switch (st.mOrientation) {
+ case TOP_BOTTOM:
+ x0 = r.left; y0 = r.top;
+ x1 = x0; y1 = level * r.bottom;
+ break;
+ case TR_BL:
+ x0 = r.right; y0 = r.top;
+ x1 = level * r.left; y1 = level * r.bottom;
+ break;
+ case RIGHT_LEFT:
+ x0 = r.right; y0 = r.top;
+ x1 = level * r.left; y1 = y0;
+ break;
+ case BR_TL:
+ x0 = r.right; y0 = r.bottom;
+ x1 = level * r.left; y1 = level * r.top;
+ break;
+ case BOTTOM_TOP:
+ x0 = r.left; y0 = r.bottom;
+ x1 = x0; y1 = level * r.top;
+ break;
+ case BL_TR:
+ x0 = r.left; y0 = r.bottom;
+ x1 = level * r.right; y1 = level * r.top;
+ break;
+ case LEFT_RIGHT:
+ x0 = r.left; y0 = r.top;
+ x1 = level * r.right; y1 = y0;
+ break;
+ default:/* TL_BR */
+ x0 = r.left; y0 = r.top;
+ x1 = level * r.right; y1 = level * r.bottom;
+ break;
+ }
+
+ mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
+ st.mColors, st.mPositions,
+ Shader.TileMode.CLAMP));
+ } else if (st.mGradient == RADIAL_GRADIENT) {
+ x0 = r.left + (r.right - r.left) * st.mCenterX;
+ y0 = r.top + (r.bottom - r.top) * st.mCenterY;
+
+ final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;
+
+ mFillPaint.setShader(new RadialGradient(x0, y0,
+ level * st.mGradientRadius, st.mColors, null,
+ Shader.TileMode.CLAMP));
+ } else if (st.mGradient == SWEEP_GRADIENT) {
+ x0 = r.left + (r.right - r.left) * st.mCenterX;
+ y0 = r.top + (r.bottom - r.top) * st.mCenterY;
+
+ float[] positions = null;
+ int[] colors = st.mColors;
+
+ if (st.mUseLevel) {
+ final int length = st.mColors.length;
+ colors = new int[length + 1];
+ System.arraycopy(st.mColors, 0, colors, 0, length);
+ colors[length] = st.mColors[length - 1];
+
+ final float fraction = 1.0f / (float) (length - 1);
+ positions = new float[length + 1];
+ final float level = (float) getLevel() / 10000.0f;
+ for (int i = 0; i < length; i++) {
+ positions[i] = i * fraction * level;
+ }
+ positions[length] = 1.0f;
+ }
+ mFillPaint.setShader(new SweepGradient(x0, y0, colors, positions));
+ }
+ }
+ }
+ return !mRect.isEmpty();
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser,
+ AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ final GradientState st = mGradientState;
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.GradientDrawable);
+
+ super.inflateWithAttributes(r, parser, a,
+ com.android.internal.R.styleable.GradientDrawable_visible);
+
+ int shapeType = a.getInt(
+ com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE);
+
+ if (shapeType == RING) {
+ st.mInnerRadius = a.getFloat(
+ com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
+ st.mThickness = a.getFloat(
+ com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
+ st.mUseLevelForShape = a.getBoolean(
+ com.android.internal.R.styleable.GradientDrawable_useLevel, true);
+ }
+
+ a.recycle();
+
+ setShape(shapeType);
+
+ int type;
+
+ final int innerDepth = parser.getDepth()+1;
+ int depth;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth=parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth) {
+ continue;
+ }
+
+ String name = parser.getName();
+
+ if (name.equals("size")) {
+ a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.GradientDrawableSize);
+ int width = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.GradientDrawableSize_width, -1);
+ int height = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.GradientDrawableSize_height, -1);
+ a.recycle();
+ setSize(width, height);
+ } else if (name.equals("gradient")) {
+ a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.GradientDrawableGradient);
+ int startColor = a.getColor(
+ com.android.internal.R.styleable.GradientDrawableGradient_startColor, 0);
+ boolean hasCenterColor = a
+ .hasValue(com.android.internal.R.styleable.GradientDrawableGradient_centerColor);
+ int centerColor = a.getColor(
+ com.android.internal.R.styleable.GradientDrawableGradient_centerColor, 0);
+ int endColor = a.getColor(
+ com.android.internal.R.styleable.GradientDrawableGradient_endColor, 0);
+ int gradientType = a.getInt(
+ com.android.internal.R.styleable.GradientDrawableGradient_type,
+ LINEAR_GRADIENT);
+
+ st.mCenterX = getFloatOrFraction(
+ a,
+ com.android.internal.R.styleable.GradientDrawableGradient_centerX,
+ 0.5f);
+
+ st.mCenterY = getFloatOrFraction(
+ a,
+ com.android.internal.R.styleable.GradientDrawableGradient_centerY,
+ 0.5f);
+
+ st.mUseLevel = a.getBoolean(
+ com.android.internal.R.styleable.GradientDrawableGradient_useLevel, false);
+ st.mGradient = gradientType;
+
+ if (gradientType == LINEAR_GRADIENT) {
+ int angle = (int)a.getFloat(
+ com.android.internal.R.styleable.GradientDrawableGradient_angle, 0);
+ angle %= 360;
+ if (angle % 45 != 0) {
+ throw new XmlPullParserException(a.getPositionDescription()
+ + "<gradient> tag requires 'angle' attribute to "
+ + "be a multiple of 45");
+ }
+
+ switch (angle) {
+ case 0:
+ st.mOrientation = Orientation.LEFT_RIGHT;
+ break;
+ case 45:
+ st.mOrientation = Orientation.BL_TR;
+ break;
+ case 90:
+ st.mOrientation = Orientation.BOTTOM_TOP;
+ break;
+ case 135:
+ st.mOrientation = Orientation.BR_TL;
+ break;
+ case 180:
+ st.mOrientation = Orientation.RIGHT_LEFT;
+ break;
+ case 225:
+ st.mOrientation = Orientation.TR_BL;
+ break;
+ case 270:
+ st.mOrientation = Orientation.TOP_BOTTOM;
+ break;
+ case 315:
+ st.mOrientation = Orientation.TL_BR;
+ break;
+ }
+ } else {
+ TypedValue tv = a.peekValue(
+ com.android.internal.R.styleable.GradientDrawableGradient_gradientRadius);
+ if (tv != null) {
+ boolean radiusRel = tv.type == TypedValue.TYPE_FRACTION;
+ st.mGradientRadius = radiusRel ?
+ tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+ } else if (gradientType == RADIAL_GRADIENT) {
+ throw new XmlPullParserException(
+ a.getPositionDescription()
+ + "<gradient> tag requires 'gradientRadius' "
+ + "attribute with radial type");
+ }
+ }
+
+ a.recycle();
+
+ if (hasCenterColor) {
+ st.mColors = new int[3];
+ st.mColors[0] = startColor;
+ st.mColors[1] = centerColor;
+ st.mColors[2] = endColor;
+
+ st.mPositions = new float[3];
+ st.mPositions[0] = 0.0f;
+ // Since 0.5f is default value, try to take the one that isn't 0.5f
+ st.mPositions[1] = st.mCenterX != 0.5f ? st.mCenterX : st.mCenterY;
+ st.mPositions[2] = 1f;
+ } else {
+ st.mColors = new int[2];
+ st.mColors[0] = startColor;
+ st.mColors[1] = endColor;
+ }
+
+ } else if (name.equals("solid")) {
+ a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.GradientDrawableSolid);
+ int argb = a.getColor(
+ com.android.internal.R.styleable.GradientDrawableSolid_color, 0);
+ a.recycle();
+ setColor(argb);
+ } else if (name.equals("stroke")) {
+ a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.GradientDrawableStroke);
+ int width = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.GradientDrawableStroke_width, 0);
+ int color = a.getColor(
+ com.android.internal.R.styleable.GradientDrawableStroke_color, 0);
+ float dashWidth = a.getDimension(
+ com.android.internal.R.styleable.GradientDrawableStroke_dashWidth, 0);
+ if (dashWidth != 0.0f) {
+ float dashGap = a.getDimension(
+ com.android.internal.R.styleable.GradientDrawableStroke_dashGap, 0);
+ setStroke(width, color, dashWidth, dashGap);
+ } else {
+ setStroke(width, color);
+ }
+ a.recycle();
+ } else if (name.equals("corners")) {
+ a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.DrawableCorners);
+ int radius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_radius, 0);
+ setCornerRadius(radius);
+ int topLeftRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius);
+ int topRightRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_topRightRadius, radius);
+ int bottomLeftRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_bottomLeftRadius, radius);
+ int bottomRightRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius);
+ if (topLeftRadius != radius && topRightRadius != radius &&
+ bottomLeftRadius != radius && bottomRightRadius != radius) {
+ setCornerRadii(new float[] {
+ topLeftRadius, topLeftRadius,
+ topRightRadius, topRightRadius,
+ bottomLeftRadius, bottomLeftRadius,
+ bottomRightRadius, bottomRightRadius
+ });
+ }
+ a.recycle();
+ } else if (name.equals("padding")) {
+ a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.GradientDrawablePadding);
+ mPadding = new Rect(
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.GradientDrawablePadding_left, 0),
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.GradientDrawablePadding_top, 0),
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.GradientDrawablePadding_right, 0),
+ a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.GradientDrawablePadding_bottom, 0));
+ a.recycle();
+ mGradientState.mPadding = mPadding;
+ } else {
+ Log.w("drawable", "Bad element under <shape>: " + name);
+ }
+ }
+ }
+
+ private static float getFloatOrFraction(TypedArray a, int index, float defaultValue) {
+ TypedValue tv = a.peekValue(index);
+ float v = defaultValue;
+ if (tv != null) {
+ boolean vIsFraction = tv.type == TypedValue.TYPE_FRACTION;
+ v = vIsFraction ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+ }
+ return v;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mGradientState.mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mGradientState.mHeight;
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ mGradientState.mChangingConfigurations = super.getChangingConfigurations();
+ return mGradientState;
+ }
+
+ final static class GradientState extends ConstantState {
+ public int mChangingConfigurations;
+ public int mShape = RECTANGLE;
+ public int mGradient = LINEAR_GRADIENT;
+ public Orientation mOrientation;
+ public int[] mColors;
+ public float[] mPositions;
+ public boolean mHasSolidColor;
+ public int mSolidColor;
+ public int mStrokeWidth = -1; // if >= 0 use stroking.
+ public int mStrokeColor;
+ public float mStrokeDashWidth;
+ public float mStrokeDashGap;
+ public float mRadius; // use this if mRadiusArray is null
+ public float[] mRadiusArray;
+ public Rect mPadding;
+ public int mWidth = -1;
+ public int mHeight = -1;
+ public float mInnerRadius;
+ public float mThickness;
+ private float mCenterX = 0.5f;
+ private float mCenterY = 0.5f;
+ private float mGradientRadius = 0.5f;
+ private boolean mUseLevel;
+ private boolean mUseLevelForShape;
+
+
+ GradientState() {
+ mOrientation = Orientation.TOP_BOTTOM;
+ }
+
+ GradientState(Orientation orientation, int[] colors) {
+ mOrientation = orientation;
+ mColors = colors;
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new GradientDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ public void setShape(int shape) {
+ mShape = shape;
+ }
+
+ public void setGradientType(int gradient) {
+ mGradient = gradient;
+ }
+
+ public void setGradientCenter(float x, float y) {
+ mCenterX = x;
+ mCenterY = y;
+ }
+
+ public void setSolidColor(int argb) {
+ mHasSolidColor = true;
+ mSolidColor = argb;
+ mColors = null;
+ }
+
+ public void setStroke(int width, int color) {
+ mStrokeWidth = width;
+ mStrokeColor = color;
+ }
+
+ public void setStroke(int width, int color, float dashWidth, float dashGap) {
+ mStrokeWidth = width;
+ mStrokeColor = color;
+ mStrokeDashWidth = dashWidth;
+ mStrokeDashGap = dashGap;
+ }
+
+ public void setCornerRadius(float radius) {
+ if (radius < 0) {
+ radius = 0;
+ }
+ mRadius = radius;
+ mRadiusArray = null;
+ }
+
+ public void setCornerRadii(float[] radii) {
+ mRadiusArray = radii;
+ if (radii == null) {
+ mRadius = 0;
+ }
+ }
+
+ public void setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ public void setGradientRadius(float gradientRadius) {
+ mGradientRadius = gradientRadius;
+ }
+ }
+
+ private GradientDrawable(GradientState state) {
+ mGradientState = state;
+ if (state.mHasSolidColor) {
+ mFillPaint.setColor(state.mSolidColor);
+ }
+ mPadding = state.mPadding;
+ if (state.mStrokeWidth >= 0) {
+ mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mStrokePaint.setStyle(Paint.Style.STROKE);
+ mStrokePaint.setStrokeWidth(state.mStrokeWidth);
+ mStrokePaint.setColor(state.mStrokeColor);
+
+ if (state.mStrokeDashWidth != 0.0f) {
+ DashPathEffect e = new DashPathEffect(new float[] {
+ state.mStrokeDashWidth, state.mStrokeDashGap}, 0);
+ mStrokePaint.setPathEffect(e);
+ }
+ }
+ mRectIsDirty = true;
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
new file mode 100644
index 0000000..fe21692
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -0,0 +1,285 @@
+/*
+ * 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.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.*;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * A Drawable that insets another Drawable by a specified distance.
+ * This is used when a View needs a background that is smaller than
+ * the View's actual bounds.
+ */
+public class InsetDrawable extends Drawable implements Drawable.Callback
+{
+ // Most of this is copied from ScaleDrawable.
+
+ /*package*/ InsetDrawable() {
+ this(null);
+ }
+
+ public InsetDrawable(Drawable drawable, int inset) {
+ this(drawable, inset, inset, inset, inset);
+ }
+
+ public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
+ int insetRight, int insetBottom) {
+ this(null);
+
+ mInsetState.mDrawable = drawable;
+ mInsetState.mInsetLeft = insetLeft;
+ mInsetState.mInsetTop = insetTop;
+ mInsetState.mInsetRight = insetRight;
+ mInsetState.mInsetBottom = insetBottom;
+
+ if (drawable != null) {
+ drawable.setCallback(this);
+ }
+ }
+
+ @Override public void inflate(Resources r, XmlPullParser parser,
+ AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ int type;
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.InsetDrawable);
+
+ super.inflateWithAttributes(r, parser, a,
+ com.android.internal.R.styleable.InsetDrawable_visible);
+
+ int drawableRes = a.getResourceId(com.android.internal.R.styleable.
+ InsetDrawable_drawable, 0);
+
+ int inLeft = a.getDimensionPixelOffset(com.android.internal.R.styleable.
+ InsetDrawable_insetLeft, 0);
+ int inTop = a.getDimensionPixelOffset(com.android.internal.R.styleable.
+ InsetDrawable_insetTop, 0);
+ int inRight = a.getDimensionPixelOffset(com.android.internal.R.styleable.
+ InsetDrawable_insetRight, 0);
+ int inBottom = a.getDimensionPixelOffset(com.android.internal.R.styleable.
+ InsetDrawable_insetBottom, 0);
+
+ a.recycle();
+
+ Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ while ((type=parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <inset> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ if (dr == null) {
+ Log.w("drawable", "No drawable specified for <inset>");
+ }
+
+ mInsetState.mDrawable = dr;
+ mInsetState.mInsetLeft = inLeft;
+ mInsetState.mInsetRight = inRight;
+ mInsetState.mInsetTop = inTop;
+ mInsetState.mInsetBottom = inBottom;
+
+ if (dr != null) {
+ dr.setCallback(this);
+ }
+ }
+
+ // overrides from Drawable.Callback
+
+ public void invalidateDrawable(Drawable who) {
+ if (mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ // overrides from Drawable
+
+ @Override
+ public void draw(Canvas canvas) {
+ mInsetState.mDrawable.draw(canvas);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mInsetState.mChangingConfigurations
+ | mInsetState.mDrawable.getChangingConfigurations();
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ boolean pad = mInsetState.mDrawable.getPadding(padding);
+
+ padding.left += mInsetState.mInsetLeft;
+ padding.right += mInsetState.mInsetRight;
+ padding.top += mInsetState.mInsetTop;
+ padding.bottom += mInsetState.mInsetBottom;
+
+ if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
+ mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ mInsetState.mDrawable.setVisible(visible, restart);
+ return super.setVisible(visible, restart);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mInsetState.mDrawable.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mInsetState.mDrawable.setColorFilter(cf);
+ }
+
+ @Override
+ public int getOpacity() {
+ return mInsetState.mDrawable.getOpacity();
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mInsetState.mDrawable.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ boolean changed = mInsetState.mDrawable.setState(state);
+ onBoundsChange(getBounds());
+ return changed;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ final Rect r = mTmpRect;
+ r.set(bounds);
+
+ r.left += mInsetState.mInsetLeft;
+ r.top += mInsetState.mInsetTop;
+ r.right -= mInsetState.mInsetRight;
+ r.bottom -= mInsetState.mInsetBottom;
+
+ mInsetState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mInsetState.mDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mInsetState.mDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mInsetState.canConstantState()) {
+ mInsetState.mChangingConfigurations = super.getChangingConfigurations();
+ return mInsetState;
+ }
+ return null;
+ }
+
+ final static class InsetState extends ConstantState {
+ InsetState(InsetState orig, InsetDrawable owner) {
+ if (orig != null) {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ mDrawable.setCallback(owner);
+ mInsetLeft = orig.mInsetLeft;
+ mInsetTop = orig.mInsetTop;
+ mInsetRight = orig.mInsetRight;
+ mInsetBottom = orig.mInsetBottom;
+ mCheckedConstantState = mCanConstantState = true;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new InsetDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ boolean canConstantState() {
+ if (!mCheckedConstantState) {
+ mCanConstantState = mDrawable.getConstantState() != null;
+ mCheckedConstantState = true;
+ }
+
+ return mCanConstantState;
+ }
+
+ Drawable mDrawable;
+ int mChangingConfigurations;
+
+ int mInsetLeft;
+ int mInsetTop;
+ int mInsetRight;
+ int mInsetBottom;
+
+ boolean mCheckedConstantState;
+ boolean mCanConstantState;
+ }
+
+ private InsetDrawable(InsetState state) {
+ InsetState as = new InsetState(state, this);
+ mInsetState = as;
+ }
+
+ private InsetState mInsetState;
+ private final Rect mTmpRect = new Rect();
+}
+
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
new file mode 100644
index 0000000..6e9d9ba
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.*;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.io.IOException;
+
+/** Drawable that manages an array of other drawables. These are drawn in array
+ order, so the element with the largest index will be drawn on top.
+*/
+public class LayerDrawable extends Drawable implements Drawable.Callback {
+
+ /* package */ LayerState mLayerState;
+
+ private int[] mPaddingL;
+ private int[] mPaddingT;
+ private int[] mPaddingR;
+ private int[] mPaddingB;
+
+ private final Rect mTmpRect = new Rect();
+
+ public LayerDrawable(Drawable[] array) {
+ this((LayerState)null);
+ int length = array.length;
+ Rec[] r = new Rec[length];
+
+ for (int i = 0; i < length; i++) {
+ r[i] = new Rec();
+ r[i].mDrawable = array[i];
+ array[i].setCallback(this);
+ mLayerState.mChildrenChangingConfigurations
+ |= array[i].getChangingConfigurations();
+ }
+ mLayerState.mNum = length;
+ mLayerState.mArray = r;
+ ensurePadding();
+ }
+
+ /* package */ LayerDrawable() {
+ this((LayerState) null);
+ }
+
+
+ /* package */ LayerDrawable(LayerState state) {
+ LayerState as = createConstantState(state);
+ mLayerState = as;
+ if (as.mNum > 0) {
+ ensurePadding();
+ }
+ }
+
+ /* package */ LayerState createConstantState(LayerState state) {
+ return new LayerState(state, this);
+ }
+
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ int type;
+
+ final int innerDepth = parser.getDepth() + 1;
+ int depth;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth || !parser.getName().equals("item")) {
+ continue;
+ }
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.LayerDrawableItem);
+
+ int left = a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.LayerDrawableItem_left, 0);
+ int top = a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.LayerDrawableItem_top, 0);
+ int right = a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.LayerDrawableItem_right, 0);
+ int bottom = a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.LayerDrawableItem_bottom, 0);
+ int drawableRes = a.getResourceId(
+ com.android.internal.R.styleable.LayerDrawableItem_drawable, 0);
+ int id = a.getResourceId(com.android.internal.R.styleable.LayerDrawableItem_id,
+ View.NO_ID);
+
+ a.recycle();
+
+ Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ while ((type = parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(parser.getPositionDescription()
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ addLayer(id, dr, left, top, right, bottom);
+ }
+
+ ensurePadding();
+ onStateChange(getState());
+ }
+
+ private void addLayer(int id, Drawable dr, int l, int t, int r, int b) {
+ final LayerState st = mLayerState;
+ int N = st.mArray != null ? st.mArray.length : 0;
+ int i = st.mNum;
+ if (i >= N) {
+ Rec[] nu = new Rec[N + 10];
+ if (i > 0) {
+ System.arraycopy(st.mArray, 0, nu, 0, i);
+ }
+ st.mArray = nu;
+ }
+
+ mLayerState.mChildrenChangingConfigurations
+ |= dr.getChangingConfigurations();
+
+ Rec rec = new Rec();
+ st.mArray[i] = rec;
+ rec.mId = id;
+ rec.mDrawable = dr;
+ rec.mInsetL = l;
+ rec.mInsetT = t;
+ rec.mInsetR = r;
+ rec.mInsetB = b;
+ st.mNum++;
+
+ dr.setCallback(this);
+ }
+
+ /**
+ * Look for a layer with the given id, and returns its {@link Drawable}.
+ *
+ * @param id The layer ID to search for.
+ * @return The {@link Drawable} of the layer that has the given id in the hierarchy or null.
+ */
+ public Drawable findDrawableByLayerId(int id) {
+ final Rec[] layers = mLayerState.mArray;
+
+ for (int i = mLayerState.mNum - 1; i >= 0; i--) {
+ if (layers[i].mId == id) {
+ return layers[i].mDrawable;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Sets the ID of a layer.
+ *
+ * @param index The index of the layer which will received the ID.
+ * @param id The ID to assign to the layer.
+ */
+ public void setId(int index, int id) {
+ mLayerState.mArray[index].mId = id;
+ }
+
+ /**
+ * Returns the number of layers contained within this.
+ * @return The number of layers.
+ */
+ // TODO: Remove this once XML inflation is there for ShapeDrawable?
+ public int getNumberOfLayers() {
+ return mLayerState.mNum;
+ }
+
+ // TODO: Remove once XML inflation...
+ public Drawable getDrawable(int index) {
+ return mLayerState.mArray[index].mDrawable;
+ }
+
+ public int getId(int index) {
+ return mLayerState.mArray[index].mId;
+ }
+
+
+ /**
+ * Sets (or replaces) the {@link Drawable} for the layer with the given id.
+ *
+ * @param id The layer ID to search for.
+ * @param drawable The replacement {@link Drawable}.
+ * @return Whether the {@link Drawable} was replaced (could return false if
+ * the id was not found).
+ */
+ public boolean setDrawableByLayerId(int id, Drawable drawable) {
+ final Rec[] layers = mLayerState.mArray;
+
+ for (int i = mLayerState.mNum - 1; i >= 0; i--) {
+ if (layers[i].mId == id) {
+ layers[i].mDrawable = drawable;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** Specify modifiers to the bounds for the drawable[index].
+ left += l
+ top += t;
+ right -= r;
+ bottom -= b;
+ */
+ public void setLayerInset(int index, int l, int t, int r, int b) {
+ Rec rec = mLayerState.mArray[index];
+ rec.mInsetL = l;
+ rec.mInsetT = t;
+ rec.mInsetR = r;
+ rec.mInsetB = b;
+ }
+
+ // overrides from Drawable.Callback
+
+ public void invalidateDrawable(Drawable who) {
+ if (mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ // overrides from Drawable
+
+ @Override
+ public void draw(Canvas canvas) {
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ for (int i=0; i<N; i++) {
+ array[i].mDrawable.draw(canvas);
+ }
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mLayerState.mChangingConfigurations
+ | mLayerState.mChildrenChangingConfigurations;
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ // Arbitrarily get the padding from the first image.
+ // Technically we should maybe do something more intelligent,
+ // like take the max padding of all the images.
+ padding.left = 0;
+ padding.top = 0;
+ padding.right = 0;
+ padding.bottom = 0;
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ for (int i=0; i<N; i++) {
+ reapplyPadding(i, array[i]);
+ padding.left += mPaddingL[i];
+ padding.top += mPaddingT[i];
+ padding.right += mPaddingR[i];
+ padding.bottom += mPaddingB[i];
+ }
+ return true;
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ boolean changed = super.setVisible(visible, restart);
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ for (int i=0; i<N; i++) {
+ array[i].mDrawable.setVisible(visible, restart);
+ }
+ return changed;
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ for (int i=0; i<N; i++) {
+ array[i].mDrawable.setDither(dither);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ for (int i=0; i<N; i++) {
+ array[i].mDrawable.setAlpha(alpha);
+ }
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ for (int i=0; i<N; i++) {
+ array[i].mDrawable.setColorFilter(cf);
+ }
+ }
+
+ @Override
+ public int getOpacity() {
+ return mLayerState.getOpacity();
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mLayerState.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ boolean paddingChanged = false;
+ boolean changed = false;
+ for (int i=0; i<N; i++) {
+ final Rec r = array[i];
+ if (r.mDrawable.setState(state)) {
+ changed = true;
+ }
+ if (reapplyPadding(i, r)) {
+ paddingChanged = true;
+ }
+ }
+ if (paddingChanged) {
+ onBoundsChange(getBounds());
+ }
+ return changed;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ boolean paddingChanged = false;
+ boolean changed = false;
+ for (int i=0; i<N; i++) {
+ final Rec r = array[i];
+ if (r.mDrawable.setLevel(level)) {
+ changed = true;
+ }
+ if (reapplyPadding(i, r)) {
+ paddingChanged = true;
+ }
+ }
+ if (paddingChanged) {
+ onBoundsChange(getBounds());
+ }
+ return changed;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ int padL=0, padT=0, padR=0, padB=0;
+ for (int i=0; i<N; i++) {
+ final Rec r = array[i];
+ r.mDrawable.setBounds(bounds.left + r.mInsetL + padL,
+ bounds.top + r.mInsetT + padT,
+ bounds.right - r.mInsetR - padR,
+ bounds.bottom - r.mInsetB - padB);
+ padL += mPaddingL[i];
+ padR += mPaddingR[i];
+ padT += mPaddingT[i];
+ padB += mPaddingB[i];
+ }
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ int width = -1;
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ int padL=0, padR=0;
+ for (int i=0; i<N; i++) {
+ final Rec r = array[i];
+ int w = r.mDrawable.getIntrinsicWidth()
+ + r.mInsetL + r.mInsetR + padL + padR;
+ if (w > width) {
+ width = w;
+ }
+ padL += mPaddingL[i];
+ padR += mPaddingR[i];
+ }
+ //System.out.println("Intrinsic width: " + width);
+ return width;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ int height = -1;
+ final Rec[] array = mLayerState.mArray;
+ final int N = mLayerState.mNum;
+ int padT=0, padB=0;
+ for (int i=0; i<N; i++) {
+ final Rec r = array[i];
+ int h = r.mDrawable.getIntrinsicHeight()
+ + r.mInsetT + r.mInsetB + + padT + padB;
+ if (h > height) {
+ height = h;
+ }
+ padT += mPaddingT[i];
+ padB += mPaddingB[i];
+ }
+ //System.out.println("Intrinsic height: " + height);
+ return height;
+ }
+
+ private boolean reapplyPadding(int i, Rec r) {
+ final Rect rect = mTmpRect;
+ r.mDrawable.getPadding(rect);
+ if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i]
+ || rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
+ mPaddingL[i] = rect.left;
+ mPaddingT[i] = rect.top;
+ mPaddingR[i] = rect.right;
+ mPaddingB[i] = rect.bottom;
+ return true;
+ }
+ return false;
+ }
+
+ private void ensurePadding() {
+ final int N = mLayerState.mNum;
+ if (mPaddingL != null && mPaddingL.length >= N) {
+ return;
+ }
+ mPaddingL = new int[N];
+ mPaddingT = new int[N];
+ mPaddingR = new int[N];
+ mPaddingB = new int[N];
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mLayerState.canConstantState()) {
+ mLayerState.mChangingConfigurations = super.getChangingConfigurations();
+ return mLayerState;
+ }
+ return null;
+ }
+
+ /* package */ static class Rec {
+ public Drawable mDrawable;
+ public int mInsetL, mInsetT, mInsetR, mInsetB;
+ public int mId;
+ }
+
+ /* package */ static class LayerState extends ConstantState {
+ int mNum;
+ Rec[] mArray;
+
+ int mChangingConfigurations;
+ int mChildrenChangingConfigurations;
+
+ private boolean mHaveOpacity = false;
+ private int mOpacity;
+
+ private boolean mHaveStateful = false;
+ private boolean mStateful;
+
+ private boolean mCheckedConstantState;
+ private boolean mCanConstantState;
+
+ LayerState(LayerState orig, LayerDrawable owner) {
+ if (orig != null) {
+ final Rec[] origRec = orig.mArray;
+ final int N = orig.mNum;
+
+ mNum = N;
+ mArray = new Rec[N];
+
+ mChangingConfigurations = orig.mChangingConfigurations;
+ mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations;
+
+ for (int i = 0; i < N; i++) {
+ final Rec r = mArray[i] = new Rec();
+ final Rec or = origRec[i];
+ r.mDrawable = or.mDrawable.getConstantState().newDrawable();
+ r.mDrawable.setCallback(owner);
+ r.mInsetL = or.mInsetL;
+ r.mInsetT = or.mInsetT;
+ r.mInsetR = or.mInsetR;
+ r.mInsetB = or.mInsetB;
+ r.mId = or.mId;
+ }
+
+ mHaveOpacity = orig.mHaveOpacity;
+ mOpacity = orig.mOpacity;
+ mHaveStateful = orig.mHaveStateful;
+ mStateful = orig.mStateful;
+ mCheckedConstantState = mCanConstantState = true;
+ } else {
+ mNum = 0;
+ mArray = null;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new LayerDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ public final int getOpacity() {
+ if (mHaveOpacity) {
+ return mOpacity;
+ }
+
+ final int N = mNum;
+ int op = N > 0 ? mArray[0].mDrawable.getOpacity()
+ : PixelFormat.TRANSPARENT;
+ for (int i = 1; i < N; i++) {
+ op = Drawable.resolveOpacity(op, mArray[i].mDrawable
+ .getOpacity());
+ }
+ mOpacity = op;
+ mHaveOpacity = true;
+ return op;
+ }
+
+ public final boolean isStateful() {
+ if (mHaveStateful) {
+ return mStateful;
+ }
+
+ boolean stateful = false;
+ final int N = mNum;
+ for (int i = 0; i < N; i++) {
+ if (mArray[i].mDrawable.isStateful()) {
+ stateful = true;
+ break;
+ }
+ }
+
+ mStateful = stateful;
+ mHaveStateful = true;
+ return stateful;
+ }
+
+ public synchronized boolean canConstantState() {
+ if (!mCheckedConstantState && mArray != null) {
+ mCanConstantState = true;
+ final int N = mNum;
+ for (int i=0; i<N; i++) {
+ if (mArray[i].mDrawable.getConstantState() == null) {
+ mCanConstantState = false;
+ break;
+ }
+ }
+ mCheckedConstantState = true;
+ }
+
+ return mCanConstantState;
+ }
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
new file mode 100644
index 0000000..61f45b3
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+/**
+ *
+ * A resource that contains a number of alternate images, each assigned a maximum numerical value.
+ * Setting the level value of the object with {@link #setLevel(int)} will load the image with the next
+ * greater or equal value assigned to its max attribute. See <a href="{@docRoot}reference/available-resources.html#levellistdrawable">
+ * Level List</a> in the Resources topic to learn how to specify this type as an XML resource. A good example use of
+ * a LevelListDrawable would be a battery level indicator icon, with different images to indicate the current
+ * battery level.
+ *
+ */
+public class LevelListDrawable extends DrawableContainer {
+ public LevelListDrawable()
+ {
+ this(null);
+ }
+
+ public void addLevel(int low, int high, Drawable drawable) {
+ if (drawable != null) {
+ mLevelListState.addLevel(low, high, drawable);
+ // in case the new state matches our current state...
+ onLevelChange(getLevel());
+ }
+ }
+
+ // overrides from Drawable
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ int idx = mLevelListState.indexOfLevel(level);
+ if (selectDrawable(idx)) {
+ return true;
+ }
+ return super.onLevelChange(level);
+ }
+
+ @Override public void inflate(Resources r, XmlPullParser parser,
+ AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ int type;
+
+ int low = 0;
+
+ final int innerDepth = parser.getDepth()+1;
+ int depth;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth=parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth || !parser.getName().equals("item")) {
+ continue;
+ }
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.LevelListDrawableItem);
+
+ low = a.getInt(
+ com.android.internal.R.styleable.LevelListDrawableItem_minLevel, 0);
+ int high = a.getInt(
+ com.android.internal.R.styleable.LevelListDrawableItem_maxLevel, 0);
+ int drawableRes = a.getResourceId(
+ com.android.internal.R.styleable.LevelListDrawableItem_drawable, 0);
+
+ a.recycle();
+
+ if (high < 0) {
+ throw new XmlPullParserException(parser.getPositionDescription()
+ + ": <item> tag requires a 'maxLevel' attribute");
+ }
+
+ Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ while ((type=parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ mLevelListState.addLevel(low, high, dr);
+ low = high+1;
+ }
+
+ onLevelChange(getLevel());
+ }
+
+ private final static class LevelListState extends DrawableContainerState
+ {
+ LevelListState(LevelListState orig, LevelListDrawable owner)
+ {
+ super(orig, owner);
+
+ if (orig != null) {
+ mLows = orig.mLows;
+ mHighs = orig.mHighs;
+ } else {
+ mLows = new int[getChildren().length];
+ mHighs = new int[getChildren().length];
+ }
+ }
+
+ public void addLevel(int low, int high, Drawable drawable)
+ {
+ int pos = addChild(drawable);
+ mLows[pos] = low;
+ mHighs[pos] = high;
+ }
+
+ public int indexOfLevel(int level)
+ {
+ final int[] lows = mLows;
+ final int[] highs = mHighs;
+ final int N = getChildCount();
+ for (int i=0; i<N; i++) {
+ if (level >= lows[i] && level <= highs[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public Drawable newDrawable()
+ {
+ return new LevelListDrawable(this);
+ }
+
+ @Override
+ public void growArray(int oldSize, int newSize)
+ {
+ super.growArray(oldSize, newSize);
+ int[] newInts = new int[newSize];
+ System.arraycopy(mLows, 0, newInts, 0, oldSize);
+ mLows = newInts;
+ newInts = new int[newSize];
+ System.arraycopy(mHighs, 0, newInts, 0, oldSize);
+ mHighs = newInts;
+ }
+
+ private int[] mLows;
+ private int[] mHighs;
+ }
+
+ private LevelListDrawable(LevelListState state)
+ {
+ LevelListState as = new LevelListState(state, this);
+ mLevelListState = as;
+ setConstantState(as);
+ onLevelChange(getLevel());
+ }
+
+ private final LevelListState mLevelListState;
+}
+
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
new file mode 100644
index 0000000..c98ef5b
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import android.graphics.*;
+
+/**
+ *
+ * A resizeable bitmap, with stretchable areas that you define. This type of image
+ * is defined in a .png file with a special format, described in <a link="../../../resources.html#ninepatch">
+ * Resources</a>.
+ *
+ */
+public class NinePatchDrawable extends Drawable {
+
+ public NinePatchDrawable(Bitmap bitmap, byte[] chunk,
+ Rect padding, String srcName) {
+ this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
+ }
+
+ public NinePatchDrawable(NinePatch patch) {
+ this(new NinePatchState(patch, null));
+ }
+
+ // overrides
+
+ @Override
+ public void draw(Canvas canvas) {
+ mNinePatch.draw(canvas, getBounds(), mPaint);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mNinePatchState.mChangingConfigurations;
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ padding.set(mPadding);
+ return true;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ getPaint().setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ getPaint().setColorFilter(cf);
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ getPaint().setDither(dither);
+ }
+
+ public Paint getPaint() {
+ if (mPaint == null) {
+ mPaint = new Paint();
+ }
+ return mPaint;
+ }
+
+ /**
+ * Retrieves the width of the source .png file (before resizing).
+ */
+ @Override
+ public int getIntrinsicWidth() {
+ return mNinePatch.getWidth();
+ }
+
+ /**
+ * Retrieves the height of the source .png file (before resizing).
+ */
+ @Override
+ public int getIntrinsicHeight() {
+ return mNinePatch.getHeight();
+ }
+
+ @Override
+ public int getMinimumWidth() {
+ return mNinePatch.getWidth();
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ return mNinePatch.getHeight();
+ }
+
+ /**
+ * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat} value of OPAQUE or TRANSLUCENT.
+ */
+ @Override
+ public int getOpacity() {
+ return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255)
+ ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+ }
+
+ @Override
+ public Region getTransparentRegion() {
+ return mNinePatch.getTransparentRegion(getBounds());
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ mNinePatchState.mChangingConfigurations = super.getChangingConfigurations();
+ return mNinePatchState;
+ }
+
+ final static class NinePatchState extends ConstantState {
+ NinePatchState(NinePatch ninePatch, Rect padding)
+ {
+ mNinePatch = ninePatch;
+ mPadding = padding;
+ }
+
+ @Override
+ public Drawable newDrawable()
+ {
+ return new NinePatchDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ final NinePatch mNinePatch;
+ final Rect mPadding;
+ int mChangingConfigurations;
+ }
+
+ private NinePatchDrawable(NinePatchState state) {
+ mNinePatchState = state;
+ mNinePatch = state.mNinePatch;
+ mPadding = state.mPadding;
+ }
+
+ private final NinePatchState mNinePatchState;
+ private final NinePatch mNinePatch;
+ private final Rect mPadding;
+ private Paint mPaint;
+}
+
diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java
new file mode 100644
index 0000000..c86fc46
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/PaintDrawable.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import android.graphics.drawable.shapes.RoundRectShape;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * Drawable that draws its bounds in the given paint, with optional
+ * rounded corners.
+*/
+public class PaintDrawable extends ShapeDrawable {
+
+ public PaintDrawable() {
+ }
+
+ public PaintDrawable(int color) {
+ getPaint().setColor(color);
+ }
+
+ /**
+ * Specify radius for the corners of the rectangle. If this is > 0, then the
+ * drawable is drawn in a round-rectangle, rather than a rectangle.
+ * @param radius the radius for the corners of the rectangle
+ */
+ public void setCornerRadius(float radius) {
+ float[] radii = null;
+ if (radius > 0) {
+ radii = new float[8];
+ for (int i = 0; i < 8; i++) {
+ radii[i] = radius;
+ }
+ }
+ setCornerRadii(radii);
+ }
+
+ /**
+ * Specify radii for each of the 4 corners. For each corner, the array
+ * contains 2 values, [X_radius, Y_radius]. The corners are ordered
+ * top-left, top-right, bottom-right, bottom-left
+ * @param radii the x and y radii of the corners
+ */
+ public void setCornerRadii(float[] radii) {
+ if (radii == null) {
+ if (getShape() != null) {
+ setShape(null);
+ }
+ } else {
+ setShape(new RoundRectShape(radii, null, null));
+ }
+ }
+
+ @Override
+ protected boolean inflateTag(String name, Resources r, XmlPullParser parser,
+ AttributeSet attrs) {
+ if (name.equals("corners")) {
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.DrawableCorners);
+ int radius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_radius, 0);
+ setCornerRadius(radius);
+
+ // now check of they have any per-corner radii
+
+ int topLeftRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius);
+ int topRightRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_topRightRadius, radius);
+ int bottomLeftRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_bottomLeftRadius, radius);
+ int bottomRightRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius);
+
+ if (topLeftRadius != radius || topRightRadius != radius ||
+ bottomLeftRadius != radius || bottomRightRadius != radius) {
+ setCornerRadii(new float[] {
+ topLeftRadius, topLeftRadius,
+ topRightRadius, topRightRadius,
+ bottomLeftRadius, bottomLeftRadius,
+ bottomRightRadius, bottomRightRadius
+ });
+ }
+ a.recycle();
+ return true;
+ }
+ return super.inflateTag(name, r, parser, attrs);
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
new file mode 100644
index 0000000..1f5d4d8
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -0,0 +1,106 @@
+/*
+ * 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.drawable;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
+import android.graphics.drawable.Drawable;
+import android.graphics.Picture;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.view.Gravity;
+
+/**
+ * Drawable subclass that wraps a Picture, allowing the picture to be used
+ * whereever a Drawable is supported.
+ */
+public class PictureDrawable extends Drawable {
+
+ private Picture mPicture;
+
+ /**
+ * Construct a new drawable referencing the specified picture. The picture
+ * may be null.
+ *
+ * @param picture The picture to associate with the drawable. May be null.
+ */
+ public PictureDrawable(Picture picture) {
+ mPicture = picture;
+ }
+
+ /**
+ * Return the picture associated with the drawable. May be null.
+ *
+ * @return the picture associated with the drawable, or null.
+ */
+ public Picture getPicture() {
+ return mPicture;
+ }
+
+ /**
+ * Associate a picture with this drawable. The picture may be null.
+ *
+ * @param picture The picture to associate with the drawable. May be null.
+ */
+ public void setPicture(Picture picture) {
+ mPicture = picture;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mPicture != null) {
+ Rect bounds = getBounds();
+ canvas.save();
+ canvas.clipRect(bounds);
+ canvas.translate(bounds.left, bounds.top);
+ canvas.drawPicture(mPicture);
+ canvas.restore();
+ }
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mPicture != null ? mPicture.getWidth() : -1;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mPicture != null ? mPicture.getHeight() : -1;
+ }
+
+ @Override
+ public int getOpacity() {
+ // not sure, so be safe
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setFilterBitmap(boolean filter) {}
+
+ @Override
+ public void setDither(boolean dither) {}
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {}
+
+ @Override
+ public void setAlpha(int alpha) {}
+}
+
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
new file mode 100644
index 0000000..c2f05ec
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2007 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.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.TypedValue;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * <p>A drawable that can rotate another drawable based on the current level
+ * value. The start and end angles of rotation can be controlled to map any
+ * circular arc to the level values range.</p>
+ */
+public class RotateDrawable extends Drawable implements Drawable.Callback {
+
+ /**
+ * <p>Create a new rotating drawable with an empty state.</p>
+ */
+ public RotateDrawable() {
+ this(null);
+ }
+
+ /**
+ * <p>Create a new rotating drawable with the specified state. A copy of
+ * this state is used as the internal state for the newly created
+ * drawable.</p>
+ *
+ * @param rotateState the state for this drawable
+ */
+ private RotateDrawable(RotateState rotateState) {
+ mState = new RotateState(rotateState, this);
+ }
+
+ public void draw(Canvas canvas) {
+ int saveCount = canvas.save();
+
+ Rect bounds = mState.mDrawable.getBounds();
+
+ int w = bounds.right - bounds.left;
+ int h = bounds.bottom - bounds.top;
+
+ final RotateState st = mState;
+
+ float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+ float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+
+ canvas.rotate(st.mCurrentDegrees, px, py);
+
+ st.mDrawable.draw(canvas);
+
+ canvas.restoreToCount(saveCount);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mState.mChangingConfigurations
+ | mState.mDrawable.getChangingConfigurations();
+ }
+
+ public void setAlpha(int alpha) {
+ mState.mDrawable.setAlpha(alpha);
+ }
+
+ public void setColorFilter(ColorFilter cf) {
+ mState.mDrawable.setColorFilter(cf);
+ }
+
+ public int getOpacity() {
+ return mState.mDrawable.getOpacity();
+ }
+
+ public void invalidateDrawable(Drawable who) {
+ if (mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ return mState.mDrawable.getPadding(padding);
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ mState.mDrawable.setVisible(visible, restart);
+ return super.setVisible(visible, restart);
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mState.mDrawable.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ boolean changed = mState.mDrawable.setState(state);
+ onBoundsChange(getBounds());
+ return changed;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ mState.mDrawable.setLevel(level);
+ onBoundsChange(getBounds());
+
+ mState.mCurrentDegrees = mState.mFromDegrees +
+ (mState.mToDegrees - mState.mFromDegrees) *
+ ((float) level / MAX_LEVEL);
+
+ invalidateSelf();
+ return true;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mState.mDrawable.setBounds(bounds.left, bounds.top,
+ bounds.right, bounds.bottom);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mState.mDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mState.mDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mState.canConstantState()) {
+ mState.mChangingConfigurations = super.getChangingConfigurations();
+ return mState;
+ }
+ return null;
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.RotateDrawable);
+
+ super.inflateWithAttributes(r, parser, a,
+ com.android.internal.R.styleable.RotateDrawable_visible);
+
+ TypedValue tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotX);
+ boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
+ float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+
+ tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotY);
+ boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
+ float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+
+ float fromDegrees = a.getFloat(
+ com.android.internal.R.styleable.RotateDrawable_fromDegrees, 0.0f);
+ float toDegrees = a.getFloat(
+ com.android.internal.R.styleable.RotateDrawable_toDegrees, 360.0f);
+
+ toDegrees = Math.max(fromDegrees, toDegrees);
+
+ int res = a.getResourceId(
+ com.android.internal.R.styleable.RotateDrawable_drawable, 0);
+ Drawable drawable = null;
+ if (res > 0) {
+ drawable = r.getDrawable(res);
+ }
+
+ a.recycle();
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
+ (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if ((drawable = Drawable.createFromXmlInner(r, parser, attrs)) == null) {
+ Log.w("drawable", "Bad element under <rotate>: "
+ + parser .getName());
+ }
+ }
+
+ if (drawable == null) {
+ Log.w("drawable", "No drawable specified for <rotate>");
+ }
+
+ mState.mDrawable = drawable;
+ mState.mPivotXRel = pivotXRel;
+ mState.mPivotX = pivotX;
+ mState.mPivotYRel = pivotYRel;
+ mState.mPivotY = pivotY;
+ mState.mFromDegrees = mState.mCurrentDegrees = fromDegrees;
+ mState.mToDegrees = toDegrees;
+
+ if (drawable != null) {
+ drawable.setCallback(this);
+ }
+ }
+
+ /**
+ * <p>Represents the state of a rotation for a given drawable. The same
+ * rotate drawable can be invoked with different states to drive several
+ * rotations at the same time.</p>
+ */
+ final static class RotateState extends Drawable.ConstantState {
+ Drawable mDrawable;
+
+ int mChangingConfigurations;
+
+ boolean mPivotXRel;
+ float mPivotX;
+ boolean mPivotYRel;
+ float mPivotY;
+
+ float mFromDegrees;
+ float mToDegrees;
+
+ float mCurrentDegrees;
+
+ public RotateState(RotateState source, RotateDrawable owner) {
+ if (source != null) {
+ mDrawable = source.mDrawable.getConstantState().newDrawable();
+ mDrawable.setCallback(owner);
+ mPivotXRel = source.mPivotXRel;
+ mPivotX = source.mPivotX;
+ mPivotYRel = source.mPivotYRel;
+ mPivotY = source.mPivotY;
+ mFromDegrees = mCurrentDegrees = source.mFromDegrees;
+ mToDegrees = source.mToDegrees;
+ mCanConstantState = mCheckedConstantState = true;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new RotateDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ public boolean canConstantState() {
+ if (!mCheckedConstantState) {
+ mCanConstantState = mDrawable.getConstantState() != null;
+ mCheckedConstantState = true;
+ }
+
+ return mCanConstantState;
+ }
+
+ private boolean mCanConstantState;
+ private boolean mCheckedConstantState;
+ }
+
+ private static final float MAX_LEVEL = 10000.0f;
+
+ private RotateState mState;
+}
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
new file mode 100644
index 0000000..c39f1fa
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.*;
+import android.view.Gravity;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * A drawable that changes the size of another drawable based on its current
+ * level value. You can control how much the child drawable changes in width
+ * and height based on the level, as well as a gravity to control where it is
+ * placed in its overall container. Most often used to implement things like
+ * progress bars.
+ */
+public class ScaleDrawable extends Drawable implements Drawable.Callback {
+ private ScaleState mScaleState;
+ private final Rect mTmpRect = new Rect();
+
+ ScaleDrawable() {
+ this(null);
+ }
+
+ public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
+ this(null);
+
+ mScaleState.mDrawable = drawable;
+ mScaleState.mGravity = gravity;
+ mScaleState.mScaleWidth = scaleWidth;
+ mScaleState.mScaleHeight = scaleHeight;
+
+ if (drawable != null) {
+ drawable.setCallback(this);
+ }
+ }
+
+ private static float getPercent(TypedArray a, int name) {
+ String s = a.getString(name);
+ if (s != null) {
+ if (s.endsWith("%")) {
+ String f = s.substring(0, s.length() - 1);
+ return Float.parseFloat(f) / 100.0f;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ int type;
+
+ TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ScaleDrawable);
+
+ float sw = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleWidth);
+ float sh = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleHeight);
+ int g = a.getInt(com.android.internal.R.styleable.ScaleDrawable_scaleGravity, Gravity.LEFT);
+ Drawable dr = a.getDrawable(com.android.internal.R.styleable.ScaleDrawable_drawable);
+
+ a.recycle();
+
+ final int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ if (dr == null) {
+ throw new IllegalArgumentException("No drawable specified for <scale>");
+ }
+
+ mScaleState.mDrawable = dr;
+ mScaleState.mScaleWidth = sw;
+ mScaleState.mScaleHeight = sh;
+ mScaleState.mGravity = g;
+ if (dr != null) {
+ dr.setCallback(this);
+ }
+ }
+
+ // overrides from Drawable.Callback
+
+ public void invalidateDrawable(Drawable who) {
+ if (mCallback != null) {
+ mCallback.invalidateDrawable(this);
+ }
+ }
+
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ if (mCallback != null) {
+ mCallback.scheduleDrawable(this, what, when);
+ }
+ }
+
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ if (mCallback != null) {
+ mCallback.unscheduleDrawable(this, what);
+ }
+ }
+
+ // overrides from Drawable
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mScaleState.mDrawable.getLevel() != 0)
+ mScaleState.mDrawable.draw(canvas);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mScaleState.mChangingConfigurations
+ | mScaleState.mDrawable.getChangingConfigurations();
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ // XXX need to adjust padding!
+ return mScaleState.mDrawable.getPadding(padding);
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ mScaleState.mDrawable.setVisible(visible, restart);
+ return super.setVisible(visible, restart);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mScaleState.mDrawable.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mScaleState.mDrawable.setColorFilter(cf);
+ }
+
+ @Override
+ public int getOpacity() {
+ return mScaleState.mDrawable.getOpacity();
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mScaleState.mDrawable.isStateful();
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ boolean changed = mScaleState.mDrawable.setState(state);
+ onBoundsChange(getBounds());
+ return changed;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ mScaleState.mDrawable.setLevel(level);
+ onBoundsChange(getBounds());
+ invalidateSelf();
+ return true;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ final Rect r = mTmpRect;
+ int level = getLevel();
+ int w = bounds.width();
+ final int iw = 0; //mScaleState.mDrawable.getIntrinsicWidth();
+ if (mScaleState.mScaleWidth > 0) {
+ w -= (int) ((w - iw) * (10000 - level) * mScaleState.mScaleWidth / 10000);
+ }
+ int h = bounds.height();
+ final int ih = 0; //mScaleState.mDrawable.getIntrinsicHeight();
+ if (mScaleState.mScaleHeight > 0) {
+ h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000);
+ }
+ Gravity.apply(mScaleState.mGravity, w, h, bounds, r);
+
+ if (w > 0 && h > 0) {
+ mScaleState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+ }
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mScaleState.mDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mScaleState.mDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ if (mScaleState.canConstantState()) {
+ mScaleState.mChangingConfigurations = super.getChangingConfigurations();
+ return mScaleState;
+ }
+ return null;
+ }
+
+ final static class ScaleState extends ConstantState {
+ ScaleState(ScaleState orig, ScaleDrawable owner) {
+ if (orig != null) {
+ mDrawable = orig.mDrawable.getConstantState().newDrawable();
+ mDrawable.setCallback(owner);
+ mScaleWidth = orig.mScaleWidth;
+ mScaleHeight = orig.mScaleHeight;
+ mGravity = orig.mGravity;
+ mCheckedConstantState = mCanConstantState = true;
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new ScaleDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ boolean canConstantState() {
+ if (!mCheckedConstantState) {
+ mCanConstantState = mDrawable.getConstantState() != null;
+ mCheckedConstantState = true;
+ }
+
+ return mCanConstantState;
+ }
+
+ Drawable mDrawable;
+ int mChangingConfigurations;
+ float mScaleWidth;
+ float mScaleHeight;
+ int mGravity;
+
+ private boolean mCheckedConstantState;
+ private boolean mCanConstantState;
+ }
+
+ private ScaleDrawable(ScaleState state) {
+ mScaleState = new ScaleState(state, this);
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
new file mode 100644
index 0000000..7e1284f
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2007 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.drawable;
+
+import android.graphics.*;
+import android.graphics.drawable.shapes.Shape;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * An object that draws primitive shapes.
+ * A ShapeDrawable takes a {@link android.graphics.drawable.shapes.Shape}
+ * object and manages its presence on the screen. If no Shape is given, then
+ * the ShapeDrawable will default to a
+ * {@link android.graphics.drawable.shapes.RectShape}.
+ */
+public class ShapeDrawable extends Drawable {
+ private ShapeState mShapeState;
+
+ /**
+ * ShapeDrawable constructor.
+ */
+ public ShapeDrawable() {
+ this((ShapeState) null);
+ }
+
+ /**
+ * Creates a ShapeDrawable with a specified Shape.
+ *
+ * @param s the Shape that this ShapeDrawable should be
+ */
+ public ShapeDrawable(Shape s) {
+ this((ShapeState) null);
+
+ mShapeState.mShape = s;
+ }
+
+ private ShapeDrawable(ShapeState state) {
+ mShapeState = new ShapeState(state);
+ }
+
+ /**
+ * Returns the Shape of this ShapeDrawable.
+ */
+ public Shape getShape() {
+ return mShapeState.mShape;
+ }
+
+ /**
+ * Sets the Shape of this ShapeDrawable.
+ */
+ public void setShape(Shape s) {
+ mShapeState.mShape = s;
+ updateShape();
+ }
+
+ /**
+ * Sets a ShaderFactory to which requests for a
+ * {@link android.graphics.Shader} object will be made.
+ *
+ * @param fact an instance of your ShaderFactory implementation
+ */
+ public void setShaderFactory(ShaderFactory fact) {
+ mShapeState.mShaderFactory = fact;
+ }
+
+ /**
+ * Returns the ShaderFactory used by this ShapeDrawable for requesting a
+ * {@link android.graphics.Shader}.
+ */
+ public ShaderFactory getShaderFactory() {
+ return mShapeState.mShaderFactory;
+ }
+
+ /**
+ * Returns the Paint used to draw the shape.
+ */
+ public Paint getPaint() {
+ return mShapeState.mPaint;
+ }
+
+ /**
+ * Sets padding for the shape.
+ *
+ * @param left padding for the left side (in pixels)
+ * @param top padding for the top (in pixels)
+ * @param right padding for the right side (in pixels)
+ * @param bottom padding for the bottom (in pixels)
+ */
+ public void setPadding(int left, int top, int right, int bottom) {
+ if ((left | top | right | bottom) == 0) {
+ mShapeState.mPadding = null;
+ } else {
+ if (mShapeState.mPadding == null) {
+ mShapeState.mPadding = new Rect();
+ }
+ mShapeState.mPadding.set(left, top, right, bottom);
+ }
+ }
+
+ /**
+ * Sets padding for this shape, defined by a Rect object.
+ * Define the padding in the Rect object as: left, top, right, bottom.
+ */
+ public void setPadding(Rect padding) {
+ if (padding == null) {
+ mShapeState.mPadding = null;
+ } else {
+ if (mShapeState.mPadding == null) {
+ mShapeState.mPadding = new Rect();
+ }
+ mShapeState.mPadding.set(padding);
+ }
+ }
+
+ /**
+ * Sets the intrinsic (default) width for this shape.
+ *
+ * @param width the intrinsic width (in pixels)
+ */
+ public void setIntrinsicWidth(int width) {
+ mShapeState.mIntrinsicWidth = width;
+ }
+
+ /**
+ * Sets the intrinsic (default) height for this shape.
+ *
+ * @param height the intrinsic height (in pixels)
+ */
+ public void setIntrinsicHeight(int height) {
+ mShapeState.mIntrinsicHeight = height;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mShapeState.mIntrinsicWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mShapeState.mIntrinsicHeight;
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ if (mShapeState.mPadding != null) {
+ padding.set(mShapeState.mPadding);
+ return true;
+ } else {
+ return super.getPadding(padding);
+ }
+ }
+
+ private static int modulateAlpha(int paintAlpha, int alpha) {
+ int scale = alpha + (alpha >>> 7); // convert to 0..256
+ return paintAlpha * scale >>> 8;
+ }
+
+ /**
+ * Called from the drawable's draw() method after the canvas has been set
+ * to draw the shape at (0,0). Subclasses can override for special effects
+ * such as multiple layers, stroking, etc.
+ */
+ protected void onDraw(Shape shape, Canvas canvas, Paint paint) {
+ shape.draw(canvas, paint);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ Rect r = getBounds();
+ Paint paint = mShapeState.mPaint;
+
+ int prevAlpha = paint.getAlpha();
+ paint.setAlpha(modulateAlpha(prevAlpha, mShapeState.mAlpha));
+
+ if (mShapeState.mShape != null) {
+ // need the save both for the translate, and for the (unknown) Shape
+ int count = canvas.save();
+ canvas.translate(r.left, r.top);
+ onDraw(mShapeState.mShape, canvas, paint);
+ canvas.restoreToCount(count);
+ } else {
+ canvas.drawRect(r, paint);
+ }
+
+ // restore
+ paint.setAlpha(prevAlpha);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations()
+ | mShapeState.mChangingConfigurations;
+ }
+
+ /**
+ * Set the alpha level for this drawable [0..255]. Note that this drawable
+ * also has a color in its paint, which has an alpha as well. These two
+ * values are automatically combined during drawing. Thus if the color's
+ * alpha is 75% (i.e. 192) and the drawable's alpha is 50% (i.e. 128), then
+ * the combined alpha that will be used during drawing will be 37.5%
+ * (i.e. 96).
+ */
+ @Override public void setAlpha(int alpha) {
+ mShapeState.mAlpha = alpha;
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ mShapeState.mPaint.setColorFilter(cf);
+ }
+
+ @Override
+ public int getOpacity() {
+ if (mShapeState.mShape == null) {
+ final Paint p = mShapeState.mPaint;
+ if (p.getXfermode() == null) {
+ final int alpha = p.getAlpha();
+ if (alpha == 0) {
+ return PixelFormat.TRANSPARENT;
+ }
+ if (alpha == 255) {
+ return PixelFormat.OPAQUE;
+ }
+ }
+ }
+ // not sure, so be safe
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setDither(boolean dither) {
+ mShapeState.mPaint.setDither(dither);
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ updateShape();
+ }
+
+ /**
+ * Subclasses override this to parse custom subelements.
+ * If you handle it, return true, else return <em>super.inflateTag(...)</em>.
+ */
+ protected boolean inflateTag(String name, Resources r, XmlPullParser parser,
+ AttributeSet attrs) {
+
+ if (name.equals("padding")) {
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.ShapeDrawablePadding);
+ setPadding(a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_left, 0),
+ a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_top, 0),
+ a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_right, 0),
+ a.getInt(com.android.internal.R.styleable.ShapeDrawablePadding_bottom, 0));
+ a.recycle();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawable);
+
+ int color = mShapeState.mPaint.getColor();
+ color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color);
+ mShapeState.mPaint.setColor(color);
+
+ setIntrinsicWidth((int)
+ a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f));
+ setIntrinsicHeight((int)
+ a.getDimension(com.android.internal.R.styleable.ShapeDrawable_height, 0f));
+
+ a.recycle();
+
+ int type;
+ final int outerDepth = parser.getDepth();
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ final String name = parser.getName();
+ // call our subclass
+ if (!inflateTag(name, r, parser, attrs)) {
+ android.util.Log.w("drawable", "Unknown element: " + name +
+ " for ShapeDrawable " + this);
+ }
+ }
+ }
+
+ private void updateShape() {
+ if (mShapeState.mShape != null) {
+ final Rect r = getBounds();
+ final int w = r.width();
+ final int h = r.height();
+
+ mShapeState.mShape.resize(w, h);
+ if (mShapeState.mShaderFactory != null) {
+ mShapeState.mPaint.setShader(mShapeState.mShaderFactory.resize(w, h));
+ }
+ }
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ mShapeState.mChangingConfigurations = super.getChangingConfigurations();
+ return mShapeState;
+ }
+
+ /**
+ * Defines the intrinsic properties of this ShapeDrawable's Shape.
+ */
+ final static class ShapeState extends ConstantState {
+ int mChangingConfigurations;
+ Paint mPaint;
+ Shape mShape;
+ Rect mPadding;
+ int mIntrinsicWidth;
+ int mIntrinsicHeight;
+ int mAlpha = 255;
+ ShaderFactory mShaderFactory;
+
+ ShapeState(ShapeState orig) {
+ if (orig != null) {
+ mPaint = orig.mPaint;
+ mShape = orig.mShape;
+ mPadding = orig.mPadding;
+ mIntrinsicWidth = orig.mIntrinsicWidth;
+ mIntrinsicHeight = orig.mIntrinsicHeight;
+ mAlpha = orig.mAlpha;
+ mShaderFactory = orig.mShaderFactory;
+ } else {
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new ShapeDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+
+ /**
+ * Base class defines a factory object that is called each time the drawable
+ * is resized (has a new width or height). Its resize() method returns a
+ * corresponding shader, or null.
+ * Implement this class if you'd like your ShapeDrawable to use a special
+ * {@link android.graphics.Shader}, such as a
+ * {@link android.graphics.LinearGradient}.
+ *
+ */
+ public static abstract class ShaderFactory {
+ /**
+ * Returns the Shader to be drawn when a Drawable is drawn.
+ * The dimensions of the Drawable are passed because they may be needed
+ * to adjust how the Shader is configured for drawing.
+ * This is called by ShapeDrawable.setShape().
+ *
+ * @param width the width of the Drawable being drawn
+ * @param height the heigh of the Drawable being drawn
+ * @return the Shader to be drawn
+ */
+ public abstract Shader resize(int width, int height);
+ }
+
+ // other subclass could wack the Shader's localmatrix based on the
+ // resize params (e.g. scaletofit, etc.). This could be used to scale
+ // a bitmap to fill the bounds without needing any other special casing.
+}
+
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
new file mode 100644
index 0000000..17d5a2e
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2006 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.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.StateSet;
+
+/**
+ *
+ * Lets you assign a number of graphic images to a single Drawable and swap out the visible item by a string
+ * ID value.
+ *
+ */
+public class StateListDrawable extends DrawableContainer {
+ public StateListDrawable()
+ {
+ this(null);
+ }
+
+ /**
+ * Add a new image/string ID to the set of images.
+ * @param stateSet - An array of resource Ids to associate with the image.
+ * Switch to this image by calling setState().
+ * @param drawable -The image to show.
+ */
+ public void addState(int[] stateSet, Drawable drawable) {
+ if (drawable != null) {
+ mStateListState.addStateSet(stateSet, drawable);
+ // in case the new state matches our current state...
+ onStateChange(getState());
+ }
+ }
+
+ @Override
+ public boolean isStateful() {
+ return true;
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ int idx = mStateListState.indexOfStateSet(stateSet);
+ if (idx < 0) {
+ idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);
+ }
+ if (selectDrawable(idx)) {
+ return true;
+ }
+ return super.onStateChange(stateSet);
+ }
+
+ @Override public void inflate(Resources r, XmlPullParser parser,
+ AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ TypedArray a = r.obtainAttributes(attrs,
+ com.android.internal.R.styleable.StateListDrawable);
+
+ super.inflateWithAttributes(r, parser, a,
+ com.android.internal.R.styleable.StateListDrawable_visible);
+
+ mStateListState.setVariablePadding(a.getBoolean(
+ com.android.internal.R.styleable.StateListDrawable_variablePadding, false));
+ mStateListState.setConstantSize(a.getBoolean(
+ com.android.internal.R.styleable.StateListDrawable_constantSize, false));
+
+ a.recycle();
+
+ int type;
+
+ final int innerDepth = parser.getDepth()+1;
+ int depth;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth=parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth || !parser.getName().equals("item")) {
+ continue;
+ }
+
+ int drawableRes = 0;
+
+ int i;
+ int j = 0;
+ final int numAttrs = attrs.getAttributeCount();
+ int[] states = new int[numAttrs];
+ for (i = 0; i < numAttrs; i++) {
+ final int stateResId = attrs.getAttributeNameResource(i);
+ if (stateResId == 0) break;
+ if (stateResId == com.android.internal.R.attr.drawable) {
+ drawableRes = attrs.getAttributeResourceValue(i, 0);
+ } else {
+ states[j++] = attrs.getAttributeBooleanValue(i, false)
+ ? stateResId
+ : -stateResId;
+ }
+ }
+ states = StateSet.trimStateSet(states, j);
+
+ Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ while ((type=parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInner(r, parser, attrs);
+ }
+
+ mStateListState.addStateSet(states, dr);
+ }
+
+ onStateChange(getState());
+ }
+
+ StateListState getStateListState() {
+ return mStateListState;
+ }
+
+ static final class StateListState extends DrawableContainerState
+ {
+ StateListState(StateListState orig, StateListDrawable owner)
+ {
+ super(orig, owner);
+
+ if (orig != null) {
+ mStateSets = orig.mStateSets;
+ } else {
+ mStateSets = new int[getChildren().length][];
+ }
+ }
+
+ int addStateSet(int[] stateSet, Drawable drawable) {
+ final int pos = addChild(drawable);
+ mStateSets[pos] = stateSet;
+ return pos;
+ }
+
+ private int indexOfStateSet(int[] stateSet)
+ {
+ final int[][] stateSets = mStateSets;
+ final int N = getChildCount();
+ for (int i=0; i<N; i++) {
+ if (StateSet.stateSetMatches(stateSets[i], stateSet)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public Drawable newDrawable()
+ {
+ return new StateListDrawable(this);
+ }
+
+ @Override
+ public void growArray(int oldSize, int newSize)
+ {
+ super.growArray(oldSize, newSize);
+ final int[][] newStateSets = new int[newSize][];
+ System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize);
+ mStateSets = newStateSets;
+ }
+
+ private int[][] mStateSets;
+ }
+
+ private StateListDrawable(StateListState state)
+ {
+ StateListState as = new StateListState(state, this);
+ mStateListState = as;
+ setConstantState(as);
+ onStateChange(getState());
+ }
+
+ private final StateListState mStateListState;
+}
+
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
new file mode 100644
index 0000000..dd65636
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -0,0 +1,222 @@
+/*
+ * 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.drawable;
+
+import android.graphics.Canvas;
+import android.os.SystemClock;
+
+/**
+ * Transition drawables are an extension of LayerDrawables and are intended to cross fade between
+ * the first and second layers. To start the transition, call {@link #startTransition(int)}. To
+ * display just the first layer, call {@link #resetTransition()}
+ *
+ */
+public class TransitionDrawable extends LayerDrawable implements Drawable.Callback {
+
+ /**
+ * A transition is about to start.
+ */
+ private static final int TRANSITION_STARTING = 0;
+
+ /**
+ * The transition has started and the animation is in progress
+ */
+ private static final int TRANSITION_RUNNING = 1;
+
+ /**
+ * No transition will be applied
+ */
+ private static final int TRANSITION_NONE = 2;
+
+ /**
+ * The current state of the transition. One of {@link #TRANSITION_STARTING},
+ * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE}
+ */
+ private int mTransitionState = TRANSITION_NONE;
+
+ private boolean mReverse;
+ private long mStartTimeMillis;
+ private int mFrom;
+ private int mTo;
+ private int mDuration;
+ private TransitionState mState;
+
+ TransitionDrawable() {
+ this(new TransitionState(null, null));
+ }
+
+ private TransitionDrawable(TransitionState state) {
+ super(state);
+ mState = state;
+ }
+
+ @Override
+ LayerState createConstantState(LayerState state) {
+ return new TransitionState((TransitionState)state, this);
+ }
+
+ /**
+ * Begin the second layer on top of the first layer.
+ *
+ * @param durationMillis The length of the transition in milliseconds
+ */
+ public void startTransition(int durationMillis) {
+ mFrom = 0;
+ mTo = 255;
+ mState.mAlpha = 0;
+ mState.mDuration = mDuration = durationMillis;
+ mReverse = false;
+ mTransitionState = TRANSITION_STARTING;
+ invalidateSelf();
+ }
+
+ /**
+ * Show only the first layer.
+ */
+ public void resetTransition() {
+ mState.mAlpha = 0;
+ mTransitionState = TRANSITION_NONE;
+ invalidateSelf();
+ }
+
+ /**
+ * Reverses the transition, picking up where the transition currently is.
+ * If the transition is not currently running, this will start the transition
+ * with the specified duration. If the transition is already running, the last
+ * known duration will be used.
+ *
+ * @param duration The duration to use if no transition is running.
+ */
+ public void reverseTransition(int duration) {
+ final long time = SystemClock.uptimeMillis();
+ // Animation is over
+ if (time - mStartTimeMillis > mState.mDuration) {
+ if (mState.mAlpha == 0) {
+ mFrom = 0;
+ mTo = 255;
+ mState.mAlpha = 0;
+ mReverse = false;
+ } else {
+ mFrom = 255;
+ mTo = 0;
+ mState.mAlpha = 255;
+ mReverse = true;
+ }
+ mDuration = mState.mDuration = duration;
+ mTransitionState = TRANSITION_STARTING;
+ invalidateSelf();
+ return;
+ }
+
+ mReverse = !mReverse;
+ mFrom = mState.mAlpha;
+ mTo = mReverse ? 0 : 255;
+ mDuration = (int) (mReverse ? time - mStartTimeMillis :
+ mState.mDuration - (time - mStartTimeMillis));
+ mTransitionState = TRANSITION_STARTING;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ boolean done = true;
+ final TransitionState state = mState;
+
+ switch (mTransitionState) {
+ case TRANSITION_STARTING:
+ mStartTimeMillis = SystemClock.uptimeMillis();
+ done = false;
+ mTransitionState = TRANSITION_RUNNING;
+ break;
+
+ case TRANSITION_RUNNING:
+ if (mStartTimeMillis >= 0) {
+ float normalized = (float)
+ (SystemClock.uptimeMillis() - mStartTimeMillis) / mDuration;
+ done = normalized >= 1.0f;
+ normalized = Math.min(normalized, 1.0f);
+ state.mAlpha = (int) (mFrom + (mTo - mFrom) * normalized);
+ }
+ break;
+ }
+
+ final int alpha = state.mAlpha;
+ final boolean crossFade = state.mCrossFade;
+ final Rec[] array = mLayerState.mArray;
+ Drawable d;
+
+ d = array[0].mDrawable;
+ if (crossFade) {
+ d.setAlpha(255 - alpha);
+ }
+ d.draw(canvas);
+ if (crossFade) {
+ d.setAlpha(0xFF);
+ }
+
+ if (alpha > 0) {
+ d = array[1].mDrawable;
+ d.setAlpha(alpha);
+ d.draw(canvas);
+ d.setAlpha(0xFF);
+ }
+
+ if (!done) {
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * Enables or disables the cross fade of the drawables. When cross fade
+ * is disabled, the first drawable is always drawn opaque. With cross
+ * fade enabled, the first drawable is drawn with the opposite alpha of
+ * the second drawable.
+ *
+ * @param enabled True to enable cross fading, false otherwise.
+ */
+ public void setCrossFadeEnabled(boolean enabled) {
+ mState.mCrossFade = enabled;
+ }
+
+ /**
+ * Indicates whether the cross fade is enabled for this transition.
+ *
+ * @return True if cross fading is enabled, false otherwise.
+ */
+ public boolean isCrossFadeEnabled() {
+ return mState.mCrossFade;
+ }
+
+ static class TransitionState extends LayerState {
+ int mAlpha = 0;
+ int mDuration;
+ boolean mCrossFade;
+
+ TransitionState(TransitionState orig, TransitionDrawable owner) {
+ super(orig, owner);
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new TransitionDrawable(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/package.html b/graphics/java/android/graphics/drawable/package.html
new file mode 100644
index 0000000..17ee865
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/package.html
@@ -0,0 +1,9 @@
+<HTML>
+<BODY>
+Provides classes to manage a variety of visual elements that are intended for
+display only, such as bitmaps and gradients. These elements are often used
+by widgets as background images or simply as indicators (for example, a volume
+level indicator). You can create most of these in XML as described in <a
+href="{@docRoot}reference/available-resources.html">Resources</a>.
+</BODY>
+</HTML>
diff --git a/graphics/java/android/graphics/drawable/shapes/ArcShape.java b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
new file mode 100644
index 0000000..b90e853
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/ArcShape.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 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.drawable.shapes;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+
+/**
+ * Creates an arc shape. The arc shape starts at a specified
+ * angle and sweeps clockwise, drawing slices of pie.
+ * The arc can be drawn to a Canvas with its own draw() method,
+ * but more graphical control is available if you instead pass
+ * the ArcShape to a {@link android.graphics.drawable.ShapeDrawable}.
+ */
+public class ArcShape extends RectShape {
+ private float mStart;
+ private float mSweep;
+
+ /**
+ * ArcShape constructor.
+ *
+ * @param startAngle the angle (in degrees) where the arc begins
+ * @param sweepAngle the sweep angle (in degrees). Anything equal to or
+ * greater than 360 results in a complete circle/oval.
+ */
+ public ArcShape(float startAngle, float sweepAngle) {
+ mStart = startAngle;
+ mSweep = sweepAngle;
+ }
+
+ @Override
+ public void draw(Canvas canvas, Paint paint) {
+ canvas.drawArc(rect(), mStart, mSweep, true, paint);
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/shapes/OvalShape.java b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
new file mode 100644
index 0000000..c914999
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 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.drawable.shapes;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+/**
+ * Defines an oval shape.
+ * The oval can be drawn to a Canvas with its own draw() method,
+ * but more graphical control is available if you instead pass
+ * the OvalShape to a {@link android.graphics.drawable.ShapeDrawable}.
+ */
+public class OvalShape extends RectShape {
+
+ /**
+ * OvalShape constructor.
+ */
+ public OvalShape() {}
+
+ @Override
+ public void draw(Canvas canvas, Paint paint) {
+ canvas.drawOval(rect(), paint);
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/shapes/PathShape.java b/graphics/java/android/graphics/drawable/shapes/PathShape.java
new file mode 100644
index 0000000..3656a0b
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/PathShape.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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.drawable.shapes;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+
+/**
+ * Creates geometric paths, utilizing the {@link android.graphics.Path} class.
+ * The path can be drawn to a Canvas with its own draw() method,
+ * but more graphical control is available if you instead pass
+ * the PathShape to a {@link android.graphics.drawable.ShapeDrawable}.
+ */
+public class PathShape extends Shape {
+ private Path mPath;
+ private float mStdWidth;
+ private float mStdHeight;
+
+ private float mScaleX; // cached from onResize
+ private float mScaleY; // cached from onResize
+
+ /**
+ * PathShape constructor.
+ *
+ * @param path a Path that defines the geometric paths for this shape
+ * @param stdWidth the standard width for the shape. Any changes to the
+ * width with resize() will result in a width scaled based
+ * on the new width divided by this width.
+ * @param stdHeight the standard height for the shape. Any changes to the
+ * height with resize() will result in a height scaled based
+ * on the new height divided by this height.
+ */
+ public PathShape(Path path, float stdWidth, float stdHeight) {
+ mPath = path;
+ mStdWidth = stdWidth;
+ mStdHeight = stdHeight;
+ }
+
+ @Override
+ public void draw(Canvas canvas, Paint paint) {
+ canvas.save();
+ canvas.scale(mScaleX, mScaleY);
+ canvas.drawPath(mPath, paint);
+ canvas.restore();
+ }
+
+ @Override
+ protected void onResize(float width, float height) {
+ mScaleX = width / mStdWidth;
+ mScaleY = height / mStdHeight;
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/shapes/RectShape.java b/graphics/java/android/graphics/drawable/shapes/RectShape.java
new file mode 100644
index 0000000..4f038ae
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/RectShape.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 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.drawable.shapes;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+
+/**
+ * Defines a rectangle shape.
+ * The rectangle can be drawn to a Canvas with its own draw() method,
+ * but more graphical control is available if you instead pass
+ * the RectShape to a {@link android.graphics.drawable.ShapeDrawable}.
+ */
+public class RectShape extends Shape {
+ private RectF mRect = new RectF();
+
+ /**
+ * RectShape constructor.
+ */
+ public RectShape() {}
+
+ @Override
+ public void draw(Canvas canvas, Paint paint) {
+ canvas.drawRect(mRect, paint);
+ }
+
+ @Override
+ protected void onResize(float width, float height) {
+ mRect.set(0, 0, width, height);
+ }
+
+ /**
+ * Returns the RectF that defines this rectangle's bounds.
+ */
+ protected final RectF rect() {
+ return mRect;
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
new file mode 100644
index 0000000..54ef3f7
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007 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.drawable.shapes;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+
+/**
+ * Creates a rounded-corner rectangle. Optionally, an inset (rounded) rectangle
+ * can be included (to make a sort of "O" shape).
+ * The rounded rectangle can be drawn to a Canvas with its own draw() method,
+ * but more graphical control is available if you instead pass
+ * the RoundRectShape to a {@link android.graphics.drawable.ShapeDrawable}.
+ */
+public class RoundRectShape extends RectShape {
+ private float[] mOuterRadii;
+ private RectF mInset;
+ private float[] mInnerRadii;
+
+ private RectF mInnerRect;
+ private Path mPath; // this is what we actually draw
+
+ /**
+ * RoundRectShape constructor.
+ * Specifies an outer (round)rect and an optional inner (round)rect.
+ *
+ * @param outerRadii An array of 8 radius values, for the outer roundrect.
+ * The first two floats are for the
+ * top-left corner (remaining pairs correspond clockwise).
+ * For no rounded corners on the outer rectangle,
+ * pass null.
+ * @param inset A RectF that specifies the distance from the inner
+ * rect to each side of the outer rect.
+ * For no inner, pass null.
+ * @param innerRadii An array of 8 radius values, for the inner roundrect.
+ * The first two floats are for the
+ * top-left corner (remaining pairs correspond clockwise).
+ * For no rounded corners on the inner rectangle,
+ * pass null.
+ * If inset parameter is null, this parameter is ignored.
+ */
+ public RoundRectShape(float[] outerRadii, RectF inset,
+ float[] innerRadii) {
+ if (outerRadii.length < 8) {
+ throw new ArrayIndexOutOfBoundsException(
+ "outer radii must have >= 8 values");
+ }
+ if (innerRadii != null && innerRadii.length < 8) {
+ throw new ArrayIndexOutOfBoundsException(
+ "inner radii must have >= 8 values");
+ }
+ mOuterRadii = outerRadii;
+ mInset = inset;
+ mInnerRadii = innerRadii;
+
+ if (inset != null) {
+ mInnerRect = new RectF();
+ }
+ mPath = new Path();
+ }
+
+ @Override
+ public void draw(Canvas canvas, Paint paint) {
+ canvas.drawPath(mPath, paint);
+ }
+
+ @Override
+ protected void onResize(float w, float h) {
+ super.onResize(w, h);
+
+ RectF r = rect();
+ mPath.reset();
+
+ if (mOuterRadii != null) {
+ mPath.addRoundRect(r, mOuterRadii, Path.Direction.CW);
+ } else {
+ mPath.addRect(r, Path.Direction.CW);
+ }
+ if (mInnerRect != null) {
+ mInnerRect.set(r.left + mInset.left, r.top + mInset.top,
+ r.right - mInset.right, r.bottom - mInset.bottom);
+ if (mInnerRect.width() < w && mInnerRect.height() < h) {
+ if (mInnerRadii != null) {
+ mPath.addRoundRect(mInnerRect, mInnerRadii,
+ Path.Direction.CCW);
+ } else {
+ mPath.addRect(mInnerRect, Path.Direction.CCW);
+ }
+ }
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java
new file mode 100644
index 0000000..fc54bc1
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/Shape.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007 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.drawable.shapes;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+/**
+ * Defines a generic graphical "shape."
+ * Any Shape can be drawn to a Canvas with its own draw() method,
+ * but more graphical control is available if you instead pass
+ * it to a {@link android.graphics.drawable.ShapeDrawable}.
+ */
+public abstract class Shape {
+ private float mWidth;
+ private float mHeight;
+
+ /**
+ * Returns the width of the Shape.
+ */
+ public final float getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Returns the height of the Shape.
+ */
+ public final float getHeight() {
+ return mHeight;
+ }
+
+
+ /**
+ * Draw this shape into the provided Canvas, with the provided Paint.
+ * Before calling this, you must call {@link #resize(float,float)}.
+ *
+ * @param canvas the Canvas within which this shape should be drawn
+ * @param paint the Paint object that defines this shape's characteristics
+ */
+ public abstract void draw(Canvas canvas, Paint paint);
+
+
+ /**
+ * Resizes the dimensions of this shape.
+ * Must be called before {@link #draw(Canvas,Paint)}.
+ *
+ * @param width the width of the shape (in pixels)
+ * @param height the height of the shape (in pixels)
+ */
+ public final void resize(float width, float height) {
+ if (width < 0) {
+ width = 0;
+ }
+ if (height < 0) {
+ height =0;
+ }
+ if (mWidth != width || mHeight != height) {
+ mWidth = width;
+ mHeight = height;
+ onResize(width, height);
+ }
+ }
+
+ /**
+ * Checks whether the Shape is opaque.
+ * Default impl returns true. Override if your subclass can be opaque.
+ *
+ * @return true if any part of the drawable is <em>not</em> opaque.
+ */
+ public boolean hasAlpha() {
+ return true;
+ }
+
+ /**
+ * Callback method called when {@link #resize(float,float)} is executed.
+ *
+ * @param width the new width of the Shape
+ * @param height the new height of the Shape
+ */
+ protected void onResize(float width, float height) {}
+}
diff --git a/graphics/java/android/graphics/drawable/shapes/package.html b/graphics/java/android/graphics/drawable/shapes/package.html
new file mode 100644
index 0000000..5bcfa0f
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Contains classes for drawing geometric shapes.
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/graphics/java/android/graphics/package.html b/graphics/java/android/graphics/package.html
new file mode 100644
index 0000000..b4a2769
--- /dev/null
+++ b/graphics/java/android/graphics/package.html
@@ -0,0 +1,6 @@
+<HTML>
+<BODY>
+Provides low level graphics tools such as canvases, color filters, points, and
+rectangles that let you handle drawing to the screen directly.
+</BODY>
+</HTML>
diff --git a/graphics/java/com/android/internal/graphics/NativeUtils.java b/graphics/java/com/android/internal/graphics/NativeUtils.java
new file mode 100644
index 0000000..c91b7d9
--- /dev/null
+++ b/graphics/java/com/android/internal/graphics/NativeUtils.java
@@ -0,0 +1,40 @@
+/*
+ * 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.internal.graphics;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+public final class NativeUtils {
+ /**
+ * This class is uninstantiable.
+ */
+ private NativeUtils() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * Scroll a rectangular portion of a canvas.
+ *
+ * @param canvas the canvas to manipulate
+ * @param src the source rectangle
+ * @param dx horizontal offset
+ * @param dy vertical offset
+ */
+ public static native boolean nativeScrollRect(Canvas canvas, Rect src,
+ int dx, int dy);
+}