InsetDrawable.java revision c2974809373697147cbe5754835cc871fb93aef1
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics.drawable; 18 19import org.xmlpull.v1.XmlPullParser; 20import org.xmlpull.v1.XmlPullParserException; 21 22import android.content.res.Resources; 23import android.content.res.TypedArray; 24import android.graphics.*; 25import android.util.AttributeSet; 26import android.util.Log; 27 28import java.io.IOException; 29 30/** 31 * A Drawable that insets another Drawable by a specified distance. 32 * This is used when a View needs a background that is smaller than 33 * the View's actual bounds. 34 * 35 * <p>It can be defined in an XML file with the <code><inset></code> element.</p> 36 * 37 * @attr ref android.R.styleable#InsetDrawable_visible 38 * @attr ref android.R.styleable#InsetDrawable_drawable 39 * @attr ref android.R.styleable#InsetDrawable_insetLeft 40 * @attr ref android.R.styleable#InsetDrawable_insetRight 41 * @attr ref android.R.styleable#InsetDrawable_insetTop 42 * @attr ref android.R.styleable#InsetDrawable_insetBottom 43 */ 44public class InsetDrawable extends Drawable implements Drawable.Callback 45{ 46 // Most of this is copied from ScaleDrawable. 47 private InsetState mInsetState; 48 private final Rect mTmpRect = new Rect(); 49 private boolean mMutated; 50 51 /*package*/ InsetDrawable() { 52 this(null, null); 53 } 54 55 public InsetDrawable(Drawable drawable, int inset) { 56 this(drawable, inset, inset, inset, inset); 57 } 58 59 public InsetDrawable(Drawable drawable, int insetLeft, int insetTop, 60 int insetRight, int insetBottom) { 61 this(null, null); 62 63 mInsetState.mDrawable = drawable; 64 mInsetState.mInsetLeft = insetLeft; 65 mInsetState.mInsetTop = insetTop; 66 mInsetState.mInsetRight = insetRight; 67 mInsetState.mInsetBottom = insetBottom; 68 69 if (drawable != null) { 70 drawable.setCallback(this); 71 } 72 } 73 74 @Override public void inflate(Resources r, XmlPullParser parser, 75 AttributeSet attrs) 76 throws XmlPullParserException, IOException { 77 int type; 78 79 TypedArray a = r.obtainAttributes(attrs, 80 com.android.internal.R.styleable.InsetDrawable); 81 82 super.inflateWithAttributes(r, parser, a, 83 com.android.internal.R.styleable.InsetDrawable_visible); 84 85 int drawableRes = a.getResourceId(com.android.internal.R.styleable. 86 InsetDrawable_drawable, 0); 87 88 int inLeft = a.getDimensionPixelOffset(com.android.internal.R.styleable. 89 InsetDrawable_insetLeft, 0); 90 int inTop = a.getDimensionPixelOffset(com.android.internal.R.styleable. 91 InsetDrawable_insetTop, 0); 92 int inRight = a.getDimensionPixelOffset(com.android.internal.R.styleable. 93 InsetDrawable_insetRight, 0); 94 int inBottom = a.getDimensionPixelOffset(com.android.internal.R.styleable. 95 InsetDrawable_insetBottom, 0); 96 97 a.recycle(); 98 99 Drawable dr; 100 if (drawableRes != 0) { 101 dr = r.getDrawable(drawableRes); 102 } else { 103 while ((type=parser.next()) == XmlPullParser.TEXT) { 104 } 105 if (type != XmlPullParser.START_TAG) { 106 throw new XmlPullParserException( 107 parser.getPositionDescription() 108 + ": <inset> tag requires a 'drawable' attribute or " 109 + "child tag defining a drawable"); 110 } 111 dr = Drawable.createFromXmlInner(r, parser, attrs); 112 } 113 114 if (dr == null) { 115 Log.w("drawable", "No drawable specified for <inset>"); 116 } 117 118 mInsetState.mDrawable = dr; 119 mInsetState.mInsetLeft = inLeft; 120 mInsetState.mInsetRight = inRight; 121 mInsetState.mInsetTop = inTop; 122 mInsetState.mInsetBottom = inBottom; 123 124 if (dr != null) { 125 dr.setCallback(this); 126 } 127 } 128 129 // overrides from Drawable.Callback 130 131 public void invalidateDrawable(Drawable who) { 132 if (mCallback != null) { 133 mCallback.invalidateDrawable(this); 134 } 135 } 136 137 public void scheduleDrawable(Drawable who, Runnable what, long when) { 138 if (mCallback != null) { 139 mCallback.scheduleDrawable(this, what, when); 140 } 141 } 142 143 public void unscheduleDrawable(Drawable who, Runnable what) { 144 if (mCallback != null) { 145 mCallback.unscheduleDrawable(this, what); 146 } 147 } 148 149 // overrides from Drawable 150 151 @Override 152 public void draw(Canvas canvas) { 153 mInsetState.mDrawable.draw(canvas); 154 } 155 156 @Override 157 public int getChangingConfigurations() { 158 return super.getChangingConfigurations() 159 | mInsetState.mChangingConfigurations 160 | mInsetState.mDrawable.getChangingConfigurations(); 161 } 162 163 @Override 164 public boolean getPadding(Rect padding) { 165 boolean pad = mInsetState.mDrawable.getPadding(padding); 166 167 padding.left += mInsetState.mInsetLeft; 168 padding.right += mInsetState.mInsetRight; 169 padding.top += mInsetState.mInsetTop; 170 padding.bottom += mInsetState.mInsetBottom; 171 172 if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight | 173 mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) { 174 return true; 175 } else { 176 return false; 177 } 178 } 179 180 @Override 181 public boolean setVisible(boolean visible, boolean restart) { 182 mInsetState.mDrawable.setVisible(visible, restart); 183 return super.setVisible(visible, restart); 184 } 185 186 @Override 187 public void setAlpha(int alpha) { 188 mInsetState.mDrawable.setAlpha(alpha); 189 } 190 191 @Override 192 public void setColorFilter(ColorFilter cf) { 193 mInsetState.mDrawable.setColorFilter(cf); 194 } 195 196 @Override 197 public int getOpacity() { 198 return mInsetState.mDrawable.getOpacity(); 199 } 200 201 @Override 202 public boolean isStateful() { 203 return mInsetState.mDrawable.isStateful(); 204 } 205 206 @Override 207 protected boolean onStateChange(int[] state) { 208 boolean changed = mInsetState.mDrawable.setState(state); 209 onBoundsChange(getBounds()); 210 return changed; 211 } 212 213 @Override 214 protected void onBoundsChange(Rect bounds) { 215 final Rect r = mTmpRect; 216 r.set(bounds); 217 218 r.left += mInsetState.mInsetLeft; 219 r.top += mInsetState.mInsetTop; 220 r.right -= mInsetState.mInsetRight; 221 r.bottom -= mInsetState.mInsetBottom; 222 223 mInsetState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom); 224 } 225 226 @Override 227 public int getIntrinsicWidth() { 228 return mInsetState.mDrawable.getIntrinsicWidth(); 229 } 230 231 @Override 232 public int getIntrinsicHeight() { 233 return mInsetState.mDrawable.getIntrinsicHeight(); 234 } 235 236 @Override 237 public ConstantState getConstantState() { 238 if (mInsetState.canConstantState()) { 239 mInsetState.mChangingConfigurations = super.getChangingConfigurations(); 240 return mInsetState; 241 } 242 return null; 243 } 244 245 @Override 246 public Drawable mutate() { 247 if (!mMutated && super.mutate() == this) { 248 mInsetState.mDrawable.mutate(); 249 mMutated = true; 250 } 251 return this; 252 } 253 254 final static class InsetState extends ConstantState { 255 Drawable mDrawable; 256 int mChangingConfigurations; 257 258 int mInsetLeft; 259 int mInsetTop; 260 int mInsetRight; 261 int mInsetBottom; 262 263 boolean mCheckedConstantState; 264 boolean mCanConstantState; 265 266 InsetState(InsetState orig, InsetDrawable owner, Resources res) { 267 if (orig != null) { 268 if (res != null) { 269 mDrawable = orig.mDrawable.getConstantState().newDrawable(res); 270 } else { 271 mDrawable = orig.mDrawable.getConstantState().newDrawable(); 272 } 273 mDrawable.setCallback(owner); 274 mInsetLeft = orig.mInsetLeft; 275 mInsetTop = orig.mInsetTop; 276 mInsetRight = orig.mInsetRight; 277 mInsetBottom = orig.mInsetBottom; 278 mCheckedConstantState = mCanConstantState = true; 279 } 280 } 281 282 @Override 283 public Drawable newDrawable() { 284 return new InsetDrawable(this, null); 285 } 286 287 @Override 288 public Drawable newDrawable(Resources res) { 289 return new InsetDrawable(this, res); 290 } 291 292 @Override 293 public int getChangingConfigurations() { 294 return mChangingConfigurations; 295 } 296 297 boolean canConstantState() { 298 if (!mCheckedConstantState) { 299 mCanConstantState = mDrawable.getConstantState() != null; 300 mCheckedConstantState = true; 301 } 302 303 return mCanConstantState; 304 } 305 } 306 307 private InsetDrawable(InsetState state, Resources res) { 308 mInsetState = new InsetState(state, this, res); 309 } 310} 311 312