/* * 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.*; import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.TypedValue; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; /** * * 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 { private NinePatchState mNinePatchState; private NinePatch mNinePatch; private Rect mPadding; private Paint mPaint; private boolean mMutated; NinePatchDrawable() { } 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)); } private void setNinePatchState(NinePatchState state) { mNinePatchState = state; mNinePatch = state.mNinePatch; mPadding = state.mPadding; if (state.mDither) setDither(state.mDither); } // 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); } @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.NinePatchDrawable); final int id = a.getResourceId(com.android.internal.R.styleable.NinePatchDrawable_src, 0); if (id == 0) { throw new XmlPullParserException(parser.getPositionDescription() + ": <nine-patch> requires a valid src attribute"); } final boolean dither = a.getBoolean( com.android.internal.R.styleable.NinePatchDrawable_dither, false); final BitmapFactory.Options options = new BitmapFactory.Options(); if (dither) { options.inDither = false; } final Rect padding = new Rect(); Bitmap bitmap = null; try { final TypedValue value = new TypedValue(); final InputStream is = r.openRawResource(id, value); bitmap = BitmapFactory.decodeStream(r, value, is, padding, options); is.close(); } catch (IOException e) { // Ignore } if (bitmap == null) { throw new XmlPullParserException(parser.getPositionDescription() + ": <nine-patch> requires a valid src attribute"); } else if (bitmap.getNinePatchChunk() == null) { throw new XmlPullParserException(parser.getPositionDescription() + ": <nine-patch> requires a valid 9-patch source image"); } setNinePatchState(new NinePatchState( new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), padding, dither)); a.recycle(); } 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; } @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { mNinePatchState = new NinePatchState(mNinePatchState); mNinePatch = mNinePatchState.mNinePatch; mPadding = mNinePatchState.mPadding; mMutated = true; } return this; } final static class NinePatchState extends ConstantState { final NinePatch mNinePatch; final Rect mPadding; final boolean mDither; int mChangingConfigurations; NinePatchState(NinePatch ninePatch, Rect padding) { this(ninePatch, padding, false); } NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) { mNinePatch = ninePatch; mPadding = rect; mDither = dither; } NinePatchState(NinePatchState state) { mNinePatch = new NinePatch(state.mNinePatch); mPadding = new Rect(state.mPadding); mChangingConfigurations = state.mChangingConfigurations; mDither = state.mDither; } @Override public Drawable newDrawable() { return new NinePatchDrawable(this); } @Override public int getChangingConfigurations() { return mChangingConfigurations; } } private NinePatchDrawable(NinePatchState state) { setNinePatchState(state); } }