/* * 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.Rect; import android.util.AttributeSet; import java.io.IOException; /** * @hide -- we are probably moving to do MipMaps in another way (more integrated * with the resource system). * * A resource that manages a number of alternate Drawables, and which actually draws the one which * size matches the most closely the drawing bounds. Providing several pre-scaled version of the * drawable helps minimizing the aliasing artifacts that can be introduced by the scaling. * *
* Use {@link #addDrawable(Drawable)} to define the different Drawables that will represent the * mipmap levels of this MipmapDrawable. The mipmap Drawable that will actually be used when this * MipmapDrawable is drawn is the one which has the smallest intrinsic height greater or equal than * the bounds' height. This selection ensures that the best available mipmap level is scaled down to * draw this MipmapDrawable. *
* * If the bounds' height is larger than the largest mipmap, the largest mipmap will be scaled up. * Note that Drawables without intrinsic height (i.e. with a negative value, such as Color) will * only be used if no other mipmap Drawable are provided. The Drawables' intrinsic heights should * not be changed after the Drawable has been added to this MipmapDrawable. * ** The different mipmaps' parameters (opacity, padding, color filter, gravity...) should typically * be similar to ensure a continuous visual appearance when the MipmapDrawable is scaled. The aspect * ratio of the different mipmaps should especially be equal. *
* * A typical example use of a MipmapDrawable would be for an image which is intended to be scaled at * various sizes, and for which one wants to provide pre-scaled versions to precisely control its * appearance. * ** The intrinsic size of a MipmapDrawable are inferred from those of the largest mipmap (in terms of * {@link Drawable#getIntrinsicHeight()}). On the opposite, its minimum * size is defined by the smallest provided mipmap. *
* It can be defined in an XML file with the<mipmap>
element.
* Each mipmap Drawable is defined in a nested <item>
. For example:
* * <mipmap xmlns:android="http://schemas.android.com/apk/res/android"> * <item android:drawable="@drawable/my_image_8" /> * <item android:drawable="@drawable/my_image_32" /> * <item android:drawable="@drawable/my_image_128" /> * </mipmap> **
* With this XML saved into the res/drawable/ folder of the project, it can be referenced as * the drawable for an {@link android.widget.ImageView}. Assuming that the heights of the provided * drawables are respectively 8, 32 and 128 pixels, the first one will be scaled down when the * bounds' height is lower or equal than 8 pixels. The second drawable will then be used up to a * height of 32 pixels and the largest drawable will be used for greater heights. *
* @attr ref android.R.styleable#MipmapDrawableItem_drawable */ public class MipmapDrawable extends DrawableContainer { private final MipmapContainerState mMipmapContainerState; private boolean mMutated; public MipmapDrawable() { this(null, null); } /** * Adds a Drawable to the list of available mipmap Drawables. The Drawable actually used when * this MipmapDrawable is drawn is determined from its bounds. * * This method has no effect if drawable is null. * * @param drawable The Drawable that will be added to list of available mipmap Drawables. */ public void addDrawable(Drawable drawable) { if (drawable != null) { mMipmapContainerState.addDrawable(drawable); onDrawableAdded(); } } private void onDrawableAdded() { // selectDrawable assumes that the container content does not change. // When a Drawable is added, the same index can correspond to a new Drawable, and since // selectDrawable has a fast exit case when oldIndex==newIndex, the new drawable could end // up not being used in place of the previous one if they happen to share the same index. // This make sure the new computed index can actually replace the previous one. selectDrawable(-1); onBoundsChange(getBounds()); } // overrides from Drawable @Override protected void onBoundsChange(Rect bounds) { final int index = mMipmapContainerState.indexForBounds(bounds); // Will call invalidateSelf() if needed selectDrawable(index); super.onBoundsChange(bounds); } @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.MipmapDrawableItem); int drawableRes = a.getResourceId( com.android.internal.R.styleable.MipmapDrawableItem_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() + ":