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>&nbsp;&nbsp;&nbsp;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>&nbsp;&nbsp;&nbsp;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