178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne/* 278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Copyright (C) 2006 The Android Open Source Project 378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Licensed under the Apache License, Version 2.0 (the "License"); 578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * you may not use this file except in compliance with the License. 678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * You may obtain a copy of the License at 778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * http://www.apache.org/licenses/LICENSE-2.0 978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 1078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Unless required by applicable law or agreed to in writing, software 1178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * distributed under the License is distributed on an "AS IS" BASIS, 1278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * See the License for the specific language governing permissions and 1478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * limitations under the License. 1578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne */ 1678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 1778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunnepackage android.graphics.drawable; 1878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 1978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunneimport org.xmlpull.v1.XmlPullParser; 2078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunneimport org.xmlpull.v1.XmlPullParserException; 2178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 2278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunneimport android.content.res.Resources; 2378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunneimport android.content.res.TypedArray; 2478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunneimport android.graphics.Rect; 2578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunneimport android.util.AttributeSet; 2678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 2778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunneimport java.io.IOException; 2878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 2978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne/** 308c7a580b34d67fefd5f777c7bd6247b2d3960608Dianne Hackborn * @hide -- we are probably moving to do MipMaps in another way (more integrated 318c7a580b34d67fefd5f777c7bd6247b2d3960608Dianne Hackborn * with the resource system). 328c7a580b34d67fefd5f777c7bd6247b2d3960608Dianne Hackborn * 3378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * A resource that manages a number of alternate Drawables, and which actually draws the one which 3478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * size matches the most closely the drawing bounds. Providing several pre-scaled version of the 3578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * drawable helps minimizing the aliasing artifacts that can be introduced by the scaling. 3678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 3778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <p> 3878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Use {@link #addDrawable(Drawable)} to define the different Drawables that will represent the 3978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * mipmap levels of this MipmapDrawable. The mipmap Drawable that will actually be used when this 4078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * MipmapDrawable is drawn is the one which has the smallest intrinsic height greater or equal than 4178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * the bounds' height. This selection ensures that the best available mipmap level is scaled down to 4278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * draw this MipmapDrawable. 4378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * </p> 4478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 4578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * If the bounds' height is larger than the largest mipmap, the largest mipmap will be scaled up. 4678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Note that Drawables without intrinsic height (i.e. with a negative value, such as Color) will 4778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * only be used if no other mipmap Drawable are provided. The Drawables' intrinsic heights should 4878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * not be changed after the Drawable has been added to this MipmapDrawable. 4978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 5078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <p> 5178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * The different mipmaps' parameters (opacity, padding, color filter, gravity...) should typically 5278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * be similar to ensure a continuous visual appearance when the MipmapDrawable is scaled. The aspect 5378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * ratio of the different mipmaps should especially be equal. 5478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * </p> 5578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 5678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * A typical example use of a MipmapDrawable would be for an image which is intended to be scaled at 5778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * various sizes, and for which one wants to provide pre-scaled versions to precisely control its 5878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * appearance. 5978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 6078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <p> 6178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * The intrinsic size of a MipmapDrawable are inferred from those of the largest mipmap (in terms of 6220fc9bfe3ad16c5f36026fc43c85d0647b75cc40Gilles Debunne * {@link Drawable#getIntrinsicHeight()}). On the opposite, its minimum 6320fc9bfe3ad16c5f36026fc43c85d0647b75cc40Gilles Debunne * size is defined by the smallest provided mipmap. 6478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * </p> 6578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 6678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * It can be defined in an XML file with the <code><mipmap></code> element. 6778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Each mipmap Drawable is defined in a nested <code><item></code>. For example: 6878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <pre> 6978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <mipmap xmlns:android="http://schemas.android.com/apk/res/android"> 7078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <item android:drawable="@drawable/my_image_8" /> 7178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <item android:drawable="@drawable/my_image_32" /> 7278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <item android:drawable="@drawable/my_image_128" /> 7378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * </mipmap> 7478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne *</pre> 7578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * <p> 7678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * With this XML saved into the res/drawable/ folder of the project, it can be referenced as 7778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * the drawable for an {@link android.widget.ImageView}. Assuming that the heights of the provided 7878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * drawables are respectively 8, 32 and 128 pixels, the first one will be scaled down when the 7978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * bounds' height is lower or equal than 8 pixels. The second drawable will then be used up to a 8078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * height of 32 pixels and the largest drawable will be used for greater heights. 8178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * </p> 8278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * @attr ref android.R.styleable#MipmapDrawableItem_drawable 8378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne */ 8478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunnepublic class MipmapDrawable extends DrawableContainer { 8578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne private final MipmapContainerState mMipmapContainerState; 8678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne private boolean mMutated; 8778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 8878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public MipmapDrawable() { 8978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne this(null, null); 9078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 9178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 9278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne /** 9378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Adds a Drawable to the list of available mipmap Drawables. The Drawable actually used when 9478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * this MipmapDrawable is drawn is determined from its bounds. 9578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 9678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * This method has no effect if drawable is null. 9778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 9878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * @param drawable The Drawable that will be added to list of available mipmap Drawables. 9978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne */ 10078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 10178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public void addDrawable(Drawable drawable) { 10278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (drawable != null) { 10378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapContainerState.addDrawable(drawable); 10478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne onDrawableAdded(); 10578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 10678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 10778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 10878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne private void onDrawableAdded() { 10978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // selectDrawable assumes that the container content does not change. 11078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // When a Drawable is added, the same index can correspond to a new Drawable, and since 11178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // selectDrawable has a fast exit case when oldIndex==newIndex, the new drawable could end 11278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // up not being used in place of the previous one if they happen to share the same index. 11378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // This make sure the new computed index can actually replace the previous one. 11478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne selectDrawable(-1); 11578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne onBoundsChange(getBounds()); 11678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 11778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 11878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // overrides from Drawable 11978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 12078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne @Override 12178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne protected void onBoundsChange(Rect bounds) { 12278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final int index = mMipmapContainerState.indexForBounds(bounds); 12378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 12478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // Will call invalidateSelf() if needed 12578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne selectDrawable(index); 12678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 12778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne super.onBoundsChange(bounds); 12878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 12978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 13078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne @Override 13178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) 13278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne throws XmlPullParserException, IOException { 13378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 13478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne super.inflate(r, parser, attrs); 13578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 13678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne int type; 13778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 13878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final int innerDepth = parser.getDepth() + 1; 13978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne int depth; 14078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 14178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne && ((depth = parser.getDepth()) >= innerDepth 14278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne || type != XmlPullParser.END_TAG)) { 14378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (type != XmlPullParser.START_TAG) { 14478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne continue; 14578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 14678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 14778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (depth > innerDepth || !parser.getName().equals("item")) { 14878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne continue; 14978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 15078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 15178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne TypedArray a = r.obtainAttributes(attrs, 15278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne com.android.internal.R.styleable.MipmapDrawableItem); 15378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 15478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne int drawableRes = a.getResourceId( 15578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne com.android.internal.R.styleable.MipmapDrawableItem_drawable, 0); 15678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 15778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne a.recycle(); 15878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 15978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne Drawable dr; 16078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (drawableRes != 0) { 16178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne dr = r.getDrawable(drawableRes); 16278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } else { 16378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne while ((type = parser.next()) == XmlPullParser.TEXT) { 16478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 16578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (type != XmlPullParser.START_TAG) { 16678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne throw new XmlPullParserException( 16778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne parser.getPositionDescription() 16878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne + ": <item> tag requires a 'drawable' attribute or " 16978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne + "child tag defining a drawable"); 17078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 17178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne dr = Drawable.createFromXmlInner(r, parser, attrs); 17278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 17378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 17478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapContainerState.addDrawable(dr); 17578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 17678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 17778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne onDrawableAdded(); 17878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 17978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 18078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne @Override 18178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public Drawable mutate() { 18278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (!mMutated && super.mutate() == this) { 18378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapContainerState.mMipmapHeights = mMipmapContainerState.mMipmapHeights.clone(); 18478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMutated = true; 18578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 18678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne return this; 18778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 18878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 18978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne private final static class MipmapContainerState extends DrawableContainerState { 19078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne private int[] mMipmapHeights; 19178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 19278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne MipmapContainerState(MipmapContainerState orig, MipmapDrawable owner, Resources res) { 19378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne super(orig, owner, res); 19478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 19578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (orig != null) { 19678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapHeights = orig.mMipmapHeights; 19778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } else { 19878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapHeights = new int[getChildren().length]; 19978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 20078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 20178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // Change the default value 20278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne setConstantSize(true); 20378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 20478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 20578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne /** 20678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Returns the index of the child mipmap drawable that will best fit the provided bounds. 20778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * This index is determined by comparing bounds' height and children intrinsic heights. 20878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * The returned mipmap index is the smallest mipmap which height is greater or equal than 20978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * the bounds' height. If the bounds' height is larger than the largest mipmap, the largest 21078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * mipmap index is returned. 21178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 21278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * @param bounds The bounds of the MipMapDrawable. 21378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * @return The index of the child Drawable that will best fit these bounds, or -1 if there 21478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * are no children mipmaps. 21578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne */ 21678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public int indexForBounds(Rect bounds) { 21778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final int boundsHeight = bounds.height(); 21878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final int N = getChildCount(); 21978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne for (int i = 0; i < N; i++) { 22078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (boundsHeight <= mMipmapHeights[i]) { 22178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne return i; 22278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 22378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 22478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 22578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // No mipmap larger than bounds found. Use largest one which will be scaled up. 22678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (N > 0) { 22778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne return N - 1; 22878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 22978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // No Drawable mipmap at all 23078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne return -1; 23178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 23278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 23378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne /** 23478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Adds a Drawable to the list of available mipmap Drawables. This list can be retrieved 23520fc9bfe3ad16c5f36026fc43c85d0647b75cc40Gilles Debunne * using {@link DrawableContainer.DrawableContainerState#getChildren()} and this method 23620fc9bfe3ad16c5f36026fc43c85d0647b75cc40Gilles Debunne * ensures that it is always sorted by increasing {@link Drawable#getIntrinsicHeight()}. 23778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * 23878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * @param drawable The Drawable that will be added to children list 23978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne */ 24078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public void addDrawable(Drawable drawable) { 24178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // Insert drawable in last position, correctly resetting cached values and 24278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // especially mComputedConstantSize 24378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne int pos = addChild(drawable); 24478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 24578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne // Bubble sort the last drawable to restore the sort by intrinsic height 24678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final int drawableHeight = drawable.getIntrinsicHeight(); 24778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 24878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne while (pos > 0) { 24978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final Drawable previousDrawable = mDrawables[pos-1]; 25078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final int previousIntrinsicHeight = previousDrawable.getIntrinsicHeight(); 25178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 25278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (drawableHeight < previousIntrinsicHeight) { 25378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mDrawables[pos] = previousDrawable; 25478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapHeights[pos] = previousIntrinsicHeight; 25578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 25678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mDrawables[pos-1] = drawable; 25778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapHeights[pos-1] = drawableHeight; 25878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne pos--; 25978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } else { 26078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne break; 26178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 26278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 26378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 26478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 26578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne /** 26678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Intrinsic sizes are those of the largest available mipmap. 26778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne * Minimum sizes are those of the smallest available mipmap. 26878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne */ 26978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne @Override 27078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne protected void computeConstantSize() { 27178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final int N = getChildCount(); 27278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne if (N > 0) { 27378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final Drawable smallestDrawable = mDrawables[0]; 27478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mConstantMinimumWidth = smallestDrawable.getMinimumWidth(); 27578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mConstantMinimumHeight = smallestDrawable.getMinimumHeight(); 27678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 27778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne final Drawable largestDrawable = mDrawables[N-1]; 27878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mConstantWidth = largestDrawable.getIntrinsicWidth(); 27978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mConstantHeight = largestDrawable.getIntrinsicHeight(); 28078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } else { 28178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mConstantWidth = mConstantHeight = -1; 28278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mConstantMinimumWidth = mConstantMinimumHeight = 0; 28378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 28478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mComputedConstantSize = true; 28578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 28678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 28778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne @Override 28878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public Drawable newDrawable() { 28978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne return new MipmapDrawable(this, null); 29078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 29178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 29278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne @Override 29378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public Drawable newDrawable(Resources res) { 29478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne return new MipmapDrawable(this, res); 29578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 29678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 29778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne @Override 29878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne public void growArray(int oldSize, int newSize) { 29978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne super.growArray(oldSize, newSize); 30078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne int[] newInts = new int[newSize]; 30178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne System.arraycopy(mMipmapHeights, 0, newInts, 0, oldSize); 30278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapHeights = newInts; 30378aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 30478aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 30578aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne 30678aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne private MipmapDrawable(MipmapContainerState state, Resources res) { 30778aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne MipmapContainerState as = new MipmapContainerState(state, this, res); 30878aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne mMipmapContainerState = as; 30978aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne setConstantState(as); 31078aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne onDrawableAdded(); 31178aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne } 31278aaa97b77d56e35e994611406deb398eb9005dbGilles Debunne} 313