• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.graphics.drawable;
18 
19 import org.xmlpull.v1.XmlPullParser;
20 import org.xmlpull.v1.XmlPullParserException;
21 
22 import android.content.res.Resources;
23 import android.content.res.TypedArray;
24 import android.graphics.*;
25 import android.util.AttributeSet;
26 import android.util.Log;
27 
28 import 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>&lt;inset></code> element. For more
36  * information, see the guide to <a
37  * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
38  *
39  * @attr ref android.R.styleable#InsetDrawable_visible
40  * @attr ref android.R.styleable#InsetDrawable_drawable
41  * @attr ref android.R.styleable#InsetDrawable_insetLeft
42  * @attr ref android.R.styleable#InsetDrawable_insetRight
43  * @attr ref android.R.styleable#InsetDrawable_insetTop
44  * @attr ref android.R.styleable#InsetDrawable_insetBottom
45  */
46 public class InsetDrawable extends Drawable implements Drawable.Callback
47 {
48     // Most of this is copied from ScaleDrawable.
49     private InsetState mInsetState;
50     private final Rect mTmpRect = new Rect();
51     private boolean mMutated;
52 
InsetDrawable()53     /*package*/ InsetDrawable() {
54         this(null, null);
55     }
56 
InsetDrawable(Drawable drawable, int inset)57     public InsetDrawable(Drawable drawable, int inset) {
58         this(drawable, inset, inset, inset, inset);
59     }
60 
InsetDrawable(Drawable drawable, int insetLeft, int insetTop, int insetRight, int insetBottom)61     public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
62                          int insetRight, int insetBottom) {
63         this(null, null);
64 
65         mInsetState.mDrawable = drawable;
66         mInsetState.mInsetLeft = insetLeft;
67         mInsetState.mInsetTop = insetTop;
68         mInsetState.mInsetRight = insetRight;
69         mInsetState.mInsetBottom = insetBottom;
70 
71         if (drawable != null) {
72             drawable.setCallback(this);
73         }
74     }
75 
inflate(Resources r, XmlPullParser parser, AttributeSet attrs)76     @Override public void inflate(Resources r, XmlPullParser parser,
77                                   AttributeSet attrs)
78     throws XmlPullParserException, IOException {
79         int type;
80 
81         TypedArray a = r.obtainAttributes(attrs,
82                 com.android.internal.R.styleable.InsetDrawable);
83 
84         super.inflateWithAttributes(r, parser, a,
85                 com.android.internal.R.styleable.InsetDrawable_visible);
86 
87         int drawableRes = a.getResourceId(com.android.internal.R.styleable.
88                                     InsetDrawable_drawable, 0);
89 
90         int inLeft = a.getDimensionPixelOffset(com.android.internal.R.styleable.
91                                     InsetDrawable_insetLeft, 0);
92         int inTop = a.getDimensionPixelOffset(com.android.internal.R.styleable.
93                                     InsetDrawable_insetTop, 0);
94         int inRight = a.getDimensionPixelOffset(com.android.internal.R.styleable.
95                                     InsetDrawable_insetRight, 0);
96         int inBottom = a.getDimensionPixelOffset(com.android.internal.R.styleable.
97                                     InsetDrawable_insetBottom, 0);
98 
99         a.recycle();
100 
101         Drawable dr;
102         if (drawableRes != 0) {
103             dr = r.getDrawable(drawableRes);
104         } else {
105             while ((type=parser.next()) == XmlPullParser.TEXT) {
106             }
107             if (type != XmlPullParser.START_TAG) {
108                 throw new XmlPullParserException(
109                         parser.getPositionDescription()
110                         + ": <inset> tag requires a 'drawable' attribute or "
111                         + "child tag defining a drawable");
112             }
113             dr = Drawable.createFromXmlInner(r, parser, attrs);
114         }
115 
116         if (dr == null) {
117             Log.w("drawable", "No drawable specified for <inset>");
118         }
119 
120         mInsetState.mDrawable = dr;
121         mInsetState.mInsetLeft = inLeft;
122         mInsetState.mInsetRight = inRight;
123         mInsetState.mInsetTop = inTop;
124         mInsetState.mInsetBottom = inBottom;
125 
126         if (dr != null) {
127             dr.setCallback(this);
128         }
129     }
130 
131     // overrides from Drawable.Callback
132 
invalidateDrawable(Drawable who)133     public void invalidateDrawable(Drawable who) {
134         final Callback callback = getCallback();
135         if (callback != null) {
136             callback.invalidateDrawable(this);
137         }
138     }
139 
scheduleDrawable(Drawable who, Runnable what, long when)140     public void scheduleDrawable(Drawable who, Runnable what, long when) {
141         final Callback callback = getCallback();
142         if (callback != null) {
143             callback.scheduleDrawable(this, what, when);
144         }
145     }
146 
unscheduleDrawable(Drawable who, Runnable what)147     public void unscheduleDrawable(Drawable who, Runnable what) {
148         final Callback callback = getCallback();
149         if (callback != null) {
150             callback.unscheduleDrawable(this, what);
151         }
152     }
153 
154     // overrides from Drawable
155 
156     @Override
draw(Canvas canvas)157     public void draw(Canvas canvas) {
158         mInsetState.mDrawable.draw(canvas);
159     }
160 
161     @Override
getChangingConfigurations()162     public int getChangingConfigurations() {
163         return super.getChangingConfigurations()
164                 | mInsetState.mChangingConfigurations
165                 | mInsetState.mDrawable.getChangingConfigurations();
166     }
167 
168     @Override
getPadding(Rect padding)169     public boolean getPadding(Rect padding) {
170         boolean pad = mInsetState.mDrawable.getPadding(padding);
171 
172         padding.left += mInsetState.mInsetLeft;
173         padding.right += mInsetState.mInsetRight;
174         padding.top += mInsetState.mInsetTop;
175         padding.bottom += mInsetState.mInsetBottom;
176 
177         if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
178                     mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) {
179             return true;
180         } else {
181             return false;
182         }
183     }
184 
185     @Override
setVisible(boolean visible, boolean restart)186     public boolean setVisible(boolean visible, boolean restart) {
187         mInsetState.mDrawable.setVisible(visible, restart);
188         return super.setVisible(visible, restart);
189     }
190 
191     @Override
setAlpha(int alpha)192     public void setAlpha(int alpha) {
193         mInsetState.mDrawable.setAlpha(alpha);
194     }
195 
196     @Override
setColorFilter(ColorFilter cf)197     public void setColorFilter(ColorFilter cf) {
198         mInsetState.mDrawable.setColorFilter(cf);
199     }
200 
201     @Override
getOpacity()202     public int getOpacity() {
203         return mInsetState.mDrawable.getOpacity();
204     }
205 
206     @Override
isStateful()207     public boolean isStateful() {
208         return mInsetState.mDrawable.isStateful();
209     }
210 
211     @Override
onStateChange(int[] state)212     protected boolean onStateChange(int[] state) {
213         boolean changed = mInsetState.mDrawable.setState(state);
214         onBoundsChange(getBounds());
215         return changed;
216     }
217 
218     @Override
onBoundsChange(Rect bounds)219     protected void onBoundsChange(Rect bounds) {
220         final Rect r = mTmpRect;
221         r.set(bounds);
222 
223         r.left += mInsetState.mInsetLeft;
224         r.top += mInsetState.mInsetTop;
225         r.right -= mInsetState.mInsetRight;
226         r.bottom -= mInsetState.mInsetBottom;
227 
228         mInsetState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
229     }
230 
231     @Override
getIntrinsicWidth()232     public int getIntrinsicWidth() {
233         return mInsetState.mDrawable.getIntrinsicWidth();
234     }
235 
236     @Override
getIntrinsicHeight()237     public int getIntrinsicHeight() {
238         return mInsetState.mDrawable.getIntrinsicHeight();
239     }
240 
241     @Override
getConstantState()242     public ConstantState getConstantState() {
243         if (mInsetState.canConstantState()) {
244             mInsetState.mChangingConfigurations = getChangingConfigurations();
245             return mInsetState;
246         }
247         return null;
248     }
249 
250     @Override
mutate()251     public Drawable mutate() {
252         if (!mMutated && super.mutate() == this) {
253             mInsetState.mDrawable.mutate();
254             mMutated = true;
255         }
256         return this;
257     }
258 
259     final static class InsetState extends ConstantState {
260         Drawable mDrawable;
261         int mChangingConfigurations;
262 
263         int mInsetLeft;
264         int mInsetTop;
265         int mInsetRight;
266         int mInsetBottom;
267 
268         boolean mCheckedConstantState;
269         boolean mCanConstantState;
270 
InsetState(InsetState orig, InsetDrawable owner, Resources res)271         InsetState(InsetState orig, InsetDrawable owner, Resources res) {
272             if (orig != null) {
273                 if (res != null) {
274                     mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
275                 } else {
276                     mDrawable = orig.mDrawable.getConstantState().newDrawable();
277                 }
278                 mDrawable.setCallback(owner);
279                 mInsetLeft = orig.mInsetLeft;
280                 mInsetTop = orig.mInsetTop;
281                 mInsetRight = orig.mInsetRight;
282                 mInsetBottom = orig.mInsetBottom;
283                 mCheckedConstantState = mCanConstantState = true;
284             }
285         }
286 
287         @Override
newDrawable()288         public Drawable newDrawable() {
289             return new InsetDrawable(this, null);
290         }
291 
292         @Override
newDrawable(Resources res)293         public Drawable newDrawable(Resources res) {
294             return new InsetDrawable(this, res);
295         }
296 
297         @Override
getChangingConfigurations()298         public int getChangingConfigurations() {
299             return mChangingConfigurations;
300         }
301 
canConstantState()302         boolean canConstantState() {
303             if (!mCheckedConstantState) {
304                 mCanConstantState = mDrawable.getConstantState() != null;
305                 mCheckedConstantState = true;
306             }
307 
308             return mCanConstantState;
309         }
310     }
311 
InsetDrawable(InsetState state, Resources res)312     private InsetDrawable(InsetState state, Resources res) {
313         mInsetState = new InsetState(state, this, res);
314     }
315 }
316 
317