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