GenericInflater.java revision 5bf291fde3dfd64f264d525534730514a279c8fc
15bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam/* 25bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Copyright (C) 2007 The Android Open Source Project 35bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 45bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Licensed under the Apache License, Version 2.0 (the "License"); 55bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * you may not use this file except in compliance with the License. 65bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * You may obtain a copy of the License at 75bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 85bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * http://www.apache.org/licenses/LICENSE-2.0 95bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 105bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Unless required by applicable law or agreed to in writing, software 115bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * distributed under the License is distributed on an "AS IS" BASIS, 125bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * See the License for the specific language governing permissions and 145bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * limitations under the License. 155bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 165bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 175bf291fde3dfd64f264d525534730514a279c8fcMaurice Lampackage com.android.setupwizardlib.items; 185bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 195bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport java.io.IOException; 205bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport java.lang.reflect.Constructor; 215bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport java.util.HashMap; 225bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 235bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport org.xmlpull.v1.XmlPullParser; 245bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport org.xmlpull.v1.XmlPullParserException; 255bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 265bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport android.content.Context; 275bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport android.content.res.XmlResourceParser; 285bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport android.util.AttributeSet; 295bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport android.util.Log; 305bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport android.util.Xml; 315bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport android.view.ContextThemeWrapper; 325bf291fde3dfd64f264d525534730514a279c8fcMaurice Lamimport android.view.InflateException; 335bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 345bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam/** 355bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Generic XML inflater. This class is modeled after {@code android.preference.GenericInflater}, 365bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * which is in turn modeled after {@code LayoutInflater}. This can be used to recursively inflate a 375bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * hierarchy of items. All items in the hierarchy must inherit the generic type {@code T}, and the 385bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * specific implementation is expected to handle inserting child items into the parent, by 395bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * implementing {@link #onAddChildItem(Object, Object)}. 405bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 415bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param <T> Type of the items to inflate 425bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 435bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Modified from android.preference.GenericInflater 445bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 455bf291fde3dfd64f264d525534730514a279c8fcMaurice Lampublic abstract class GenericInflater<T> { 465bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 475bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private static final String TAG = "GenericInflater"; 485bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private static final boolean DEBUG = false; 495bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 505bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam protected final Context mContext; 515bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 525bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam // these are optional, set by the caller 535bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private boolean mFactorySet; 545bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private Factory<T> mFactory; 555bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 565bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private final Object[] mConstructorArgs = new Object[2]; 575bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 585bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private static final Class[] mConstructorSignature = new Class[] { 595bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam Context.class, AttributeSet.class}; 605bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 615bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private static final HashMap<String, Constructor<?>> sConstructorMap = new HashMap<>(); 625bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 635bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private String mDefaultPackage; 645bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 655bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public interface Factory<T> { 665bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 675bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Hook you can supply that is called when inflating from a 685bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * inflater. You can use this to customize the tag 695bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * names available in your XML files. 705bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <p> 715bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Note that it is good practice to prefix these custom names with your 725bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * package (i.e., com.coolcompany.apps) to avoid conflicts with system 735bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * names. 745bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 755bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param name Tag name to be inflated. 765bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param context The context the item is being created in. 775bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param attrs Inflation attributes as specified in XML file. 785bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return Newly created item. Return null for the default behavior. 795bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 805bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam T onCreateItem(String name, Context context, AttributeSet attrs); 815bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 825bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 835bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private static class FactoryMerger<T> implements Factory<T> { 845bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private final Factory<T> mF1, mF2; 855bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 865bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam FactoryMerger(Factory<T> f1, Factory<T> f2) { 875bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mF1 = f1; 885bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mF2 = f2; 895bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 905bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 915bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public T onCreateItem(String name, Context context, AttributeSet attrs) { 925bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam T v = mF1.onCreateItem(name, context, attrs); 935bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (v != null) return v; 945bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return mF2.onCreateItem(name, context, attrs); 955bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 965bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 975bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 985bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 995bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Create a new inflater instance associated with a 1005bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * particular Context. 1015bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 1025bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param context The Context in which this inflater will 1035bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * create its items; most importantly, this supplies the theme 1045bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * from which the default values for their attributes are 1055bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * retrieved. 1065bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1075bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam protected GenericInflater(Context context) { 1085bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mContext = context; 1095bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1105bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 1115bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 1125bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Create a new inflater instance that is a copy of an 1135bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * existing inflater, optionally with its Context 1145bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * changed. For use in implementing {@link #cloneInContext}. 1155bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 1165bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param original The original inflater to copy. 1175bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param newContext The new Context to use. 1185bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1195bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam protected GenericInflater(GenericInflater<T> original, Context newContext) { 1205bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mContext = newContext; 1215bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mFactory = original.mFactory; 1225bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1235bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 1245bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 1255bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Create a copy of the existing inflater object, with the copy 1265bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * pointing to a different Context than the original. This is used by 1275bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * {@link ContextThemeWrapper} to create a new inflater to go along 1285bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * with the new Context theme. 1295bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 1305bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param newContext The new Context to associate with the new inflater. 1315bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * May be the same as the original Context if desired. 1325bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 1335bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return Returns a brand spanking new inflater object associated with 1345bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * the given Context. 1355bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1365bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public abstract GenericInflater cloneInContext(Context newContext); 1375bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 1385bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 1395bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Sets the default package that will be searched for classes to construct 1405bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * for tag names that have no explicit package. 1415bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 1425bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param defaultPackage The default package. This will be prepended to the 1435bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * tag name, so it should end with a period. 1445bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1455bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public void setDefaultPackage(String defaultPackage) { 1465bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mDefaultPackage = defaultPackage; 1475bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1485bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 1495bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 1505bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Returns the default package, or null if it is not set. 1515bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 1525bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @see #setDefaultPackage(String) 1535bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return The default package. 1545bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1555bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public String getDefaultPackage() { 1565bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return mDefaultPackage; 1575bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1585bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 1595bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 1605bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Return the context we are running in, for access to resources, class 1615bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * loader, etc. 1625bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1635bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public Context getContext() { 1645bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return mContext; 1655bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1665bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 1675bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 1685bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Return the current factory (or null). This is called on each element 1695bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * name. If the factory returns an item, add that to the hierarchy. If it 1705bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * returns null, proceed to call onCreateItem(name). 1715bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1725bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public final Factory<T> getFactory() { 1735bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return mFactory; 1745bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1755bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 1765bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 1775bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Attach a custom Factory interface for creating items while using this 1785bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * inflater. This must not be null, and can only be set 1795bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * once; after setting, you can not change the factory. This is called on 1805bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * each element name as the XML is parsed. If the factory returns an item, 1815bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * that is added to the hierarchy. If it returns null, the next factory 1825bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * default {@link #onCreateItem} method is called. 1835bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <p> 1845bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * If you have an existing inflater and want to add your 1855bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * own factory to it, use {@link #cloneInContext} to clone the existing 1865bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * instance and then you can use this function (once) on the returned new 1875bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * instance. This will merge your own factory with whatever factory the 1885bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * original instance is using. 1895bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 1905bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public void setFactory(Factory<T> factory) { 1915bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (mFactorySet) { 1925bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw new IllegalStateException("" + 1935bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam "A factory has already been set on this inflater"); 1945bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1955bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (factory == null) { 1965bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw new NullPointerException("Given factory can not be null"); 1975bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 1985bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mFactorySet = true; 1995bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (mFactory == null) { 2005bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mFactory = factory; 2015bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } else { 2025bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mFactory = new FactoryMerger<>(factory, mFactory); 2035bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 2045bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 2055bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 2065bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public T inflate(int resource) { 2075bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return inflate(resource, null); 2085bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 2095bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 2105bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 2115bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 2125bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Inflate a new item hierarchy from the specified xml resource. Throws 2135bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * InflaterException if there is an error. 2145bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 2155bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param resource ID for an XML resource to load (e.g., 2165bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <code>R.layout.main_page</code>) 2175bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param root Optional parent of the generated hierarchy. 2185bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return The root of the inflated hierarchy. If root was supplied, 2195bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * this is the root item; otherwise it is the root of the inflated 2205bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * XML file. 2215bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 2225bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public T inflate(int resource, T root) { 2235bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return inflate(resource, root, root != null); 2245bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 2255bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 2265bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 2275bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Inflate a new hierarchy from the specified xml node. Throws 2285bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * InflaterException if there is an error. * 2295bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <p> 2305bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <em><strong>Important</strong></em> For performance 2315bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * reasons, inflation relies heavily on pre-processing of XML files 2325bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * that is done at build time. Therefore, it is not currently possible to 2335bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * use inflater with an XmlPullParser over a plain XML file at runtime. 2345bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 2355bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param parser XML dom node containing the description of the 2365bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * hierarchy. 2375bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param root Optional parent of the generated hierarchy. 2385bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return The root of the inflated hierarchy. If root was supplied, 2395bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * this is the that; otherwise it is the root of the inflated 2405bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * XML file. 2415bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 2425bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public T inflate(XmlPullParser parser, T root) { 2435bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return inflate(parser, root, root != null); 2445bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 2455bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 2465bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 2475bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Inflate a new hierarchy from the specified xml resource. Throws 2485bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * InflaterException if there is an error. 2495bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 2505bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param resource ID for an XML resource to load (e.g., 2515bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <code>R.layout.main_page</code>) 2525bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param root Optional root to be the parent of the generated hierarchy (if 2535bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <em>attachToRoot</em> is true), or else simply an object that 2545bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * provides a set of values for root of the returned 2555bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * hierarchy (if <em>attachToRoot</em> is false.) 2565bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param attachToRoot Whether the inflated hierarchy should be attached to 2575bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * the root parameter? 2585bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return The root of the inflated hierarchy. If root was supplied and 2595bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * attachToRoot is true, this is root; otherwise it is the root of 2605bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * the inflated XML file. 2615bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 2625bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public T inflate(int resource, T root, boolean attachToRoot) { 2635bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "INFLATING from resource: " + resource); 2645bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam XmlResourceParser parser = getContext().getResources().getXml(resource); 2655bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam try { 2665bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return inflate(parser, root, attachToRoot); 2675bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } finally { 2685bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam parser.close(); 2695bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 2705bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 2715bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 2725bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 2735bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Inflate a new hierarchy from the specified XML node. Throws 2745bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * InflaterException if there is an error. 2755bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <p> 2765bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <em><strong>Important</strong></em> For performance 2775bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * reasons, inflation relies heavily on pre-processing of XML files 2785bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * that is done at build time. Therefore, it is not currently possible to 2795bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * use inflater with an XmlPullParser over a plain XML file at runtime. 2805bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 2815bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param parser XML dom node containing the description of the 2825bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * hierarchy. 2835bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param root Optional to be the parent of the generated hierarchy (if 2845bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <em>attachToRoot</em> is true), or else simply an object that 2855bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * provides a set of values for root of the returned 2865bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * hierarchy (if <em>attachToRoot</em> is false.) 2875bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param attachToRoot Whether the inflated hierarchy should be attached to 2885bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * the root parameter? 2895bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return The root of the inflated hierarchy. If root was supplied and 2905bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * attachToRoot is true, this is root; otherwise it is the root of 2915bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * the inflated XML file. 2925bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 2935bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public T inflate(XmlPullParser parser, T root, boolean attachToRoot) { 2945bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam synchronized (mConstructorArgs) { 2955bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam final AttributeSet attrs = Xml.asAttributeSet(parser); 2965bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam mConstructorArgs[0] = mContext; 2975bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam T result; 2985bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 2995bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam try { 3005bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam // Look for the root node. 3015bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam int type; 3025bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam while ((type = parser.next()) != XmlPullParser.START_TAG 3035bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam && type != XmlPullParser.END_DOCUMENT) { 3045bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3055bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3065bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (type != XmlPullParser.START_TAG) { 3075bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw new InflateException(parser.getPositionDescription() 3085bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + ": No start tag found!"); 3095bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3105bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3115bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) { 3125bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam Log.v(TAG, "**************************"); 3135bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam Log.v(TAG, "Creating root: " 3145bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + parser.getName()); 3155bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam Log.v(TAG, "**************************"); 3165bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3175bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam // Temp is the root that was found in the xml 3185bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam T xmlRoot = createItemFromTag(parser, parser.getName(), attrs); 3195bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3205bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam result = onMergeRoots(root, attachToRoot, xmlRoot); 3215bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3225bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "-----> start inflating children"); 3235bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam // Inflate all children under temp 3245bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam rInflate(parser, result, attrs); 3255bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "-----> done inflating children"); 3265bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } catch (XmlPullParserException e) { 3275bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam InflateException ex = new InflateException(e.getMessage()); 3285bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam ex.initCause(e); 3295bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw ex; 3305bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } catch (IOException e) { 3315bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam InflateException ex = new InflateException( 3325bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam parser.getPositionDescription() 3335bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + ": " + e.getMessage()); 3345bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam ex.initCause(e); 3355bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw ex; 3365bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3375bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3385bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return result; 3395bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3405bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3415bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3425bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 3435bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Low-level function for instantiating by name. This attempts to 3445bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * instantiate class of the given <var>name</var> found in this 3455bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * inflater's ClassLoader. 3465bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 3475bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * <p> 3485bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * There are two things that can happen in an error case: either the 3495bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * exception describing the error will be thrown, or a null will be 3505bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * returned. You must deal with both possibilities -- the former will happen 3515bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * the first time createItem() is called for a class of a particular name, 3525bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * the latter every time there-after for that class name. 3535bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 3545bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param name The full name of the class to be instantiated. 3555bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param attrs The XML attributes supplied for this instance. 3565bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 3575bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return The newly instantiated item, or null. 3585bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 3595bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam public final T createItem(String name, String prefix, AttributeSet attrs) 3605bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throws ClassNotFoundException, InflateException { 3615bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam Constructor constructor = sConstructorMap.get(name); 3625bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3635bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam try { 3645bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (constructor == null) { 3655bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam // Class not found in the cache, see if it's real, 3665bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam // and try to add it 3675bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam Class<?> clazz = mContext.getClassLoader().loadClass( 3685bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam prefix != null ? (prefix + name) : name); 3695bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam constructor = clazz.getConstructor(mConstructorSignature); 3705bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam constructor.setAccessible(true); 3715bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam sConstructorMap.put(name, constructor); 3725bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3735bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3745bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam Object[] args = mConstructorArgs; 3755bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam args[1] = attrs; 3765bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam //noinspection unchecked 3775bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return (T) constructor.newInstance(args); 3785bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } catch (NoSuchMethodException e) { 3795bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam InflateException ie = new InflateException(attrs.getPositionDescription() 3805bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + ": Error inflating class " 3815bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + (prefix != null ? (prefix + name) : name)); 3825bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam ie.initCause(e); 3835bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw ie; 3845bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3855bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } catch (ClassNotFoundException e) { 3865bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam // If loadClass fails, we should propagate the exception. 3875bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw e; 3885bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } catch (Exception e) { 3895bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam InflateException ie = new InflateException(attrs.getPositionDescription() 3905bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + ": Error inflating class " 3915bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + (prefix != null ? (prefix + name) : name)); 3925bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam ie.initCause(e); 3935bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw ie; 3945bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3955bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 3965bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 3975bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 3985bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * This routine is responsible for creating the correct subclass of item 3995bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * given the xml element name. Override it to handle custom item objects. If 4005bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * you override this in your subclass be sure to call through to 4015bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * super.onCreateItem(name) for names you do not recognize. 4025bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 4035bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param name The fully qualified class name of the item to be create. 4045bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param attrs An AttributeSet of attributes to apply to the item. 4055bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return The item created. 4065bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 4075bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam protected T onCreateItem(String name, AttributeSet attrs) throws ClassNotFoundException { 4085bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return createItem(name, mDefaultPackage, attrs); 4095bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4105bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4115bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private T createItemFromTag(XmlPullParser parser, String name, AttributeSet attrs) { 4125bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "******** Creating item: " + name); 4135bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4145bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam try { 4155bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam T item = (mFactory == null) ? null : mFactory.onCreateItem(name, mContext, attrs); 4165bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4175bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (item == null) { 4185bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (-1 == name.indexOf('.')) { 4195bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam item = onCreateItem(name, attrs); 4205bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } else { 4215bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam item = createItem(name, null, attrs); 4225bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4235bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4245bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4255bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "Created item is: " + item); 4265bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return item; 4275bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4285bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } catch (InflateException e) { 4295bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw e; 4305bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4315bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } catch (Exception e) { 4325bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam InflateException ie = new InflateException(attrs 4335bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam .getPositionDescription() 4345bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam + ": Error inflating class " + name); 4355bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam ie.initCause(e); 4365bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throw ie; 4375bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4385bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4395bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4405bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 4415bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Recursive method used to descend down the xml hierarchy and instantiate 4425bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * items, instantiate their children, and then call onFinishInflate(). 4435bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 4445bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam private void rInflate(XmlPullParser parser, T node, final AttributeSet attrs) 4455bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam throws XmlPullParserException, IOException { 4465bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam final int depth = parser.getDepth(); 4475bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4485bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam int type; 4495bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam while (((type = parser.next()) != XmlPullParser.END_TAG || 4505bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { 4515bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4525bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (type != XmlPullParser.START_TAG) { 4535bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam continue; 4545bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4555bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4565bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (onCreateCustomFromTag(parser, node, attrs)) { 4575bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam continue; 4585bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4595bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4605bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "Now inflating tag: " + parser.getName()); 4615bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam String name = parser.getName(); 4625bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4635bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam T item = createItemFromTag(parser, name, attrs); 4645bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4655bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "Creating params from parent: " + node); 4665bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4675bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam onAddChildItem(node, item); 4685bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4695bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4705bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "-----> start inflating children"); 4715bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam rInflate(parser, item, attrs); 4725bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam if (DEBUG) Log.v(TAG, "-----> done inflating children"); 4735bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4745bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4755bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4765bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam /** 4775bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * Before this inflater tries to create an item from the tag, this method 4785bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * will be called. The parser will be pointing to the start of a tag, you 4795bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * must stop parsing and return when you reach the end of this element! 4805bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * 4815bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param parser XML dom node containing the description of the hierarchy. 4825bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param node The item that should be the parent of whatever you create. 4835bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @param attrs An AttributeSet of attributes to apply to the item. 4845bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * @return Whether you created a custom object (true), or whether this 4855bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam * inflater should proceed to create an item. 4865bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam */ 4875bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam protected boolean onCreateCustomFromTag(XmlPullParser parser, T node, 4885bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam final AttributeSet attrs) throws XmlPullParserException { 4895bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return false; 4905bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4915bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4925bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam protected abstract void onAddChildItem(T parent, T child); 4935bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam 4945bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam protected T onMergeRoots(T givenRoot, boolean attachToGivenRoot, T xmlRoot) { 4955bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam return xmlRoot; 4965bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam } 4975bf291fde3dfd64f264d525534730514a279c8fcMaurice Lam} 498