102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette/*
202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * Copyright (C) 2015 The Android Open Source Project
302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette *
402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License");
502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * you may not use this file except in compliance with the License.
602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * You may obtain a copy of the License at
702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette *
802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette *      http://www.apache.org/licenses/LICENSE-2.0
902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette *
1002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * Unless required by applicable law or agreed to in writing, software
1102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS,
1202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * See the License for the specific language governing permissions and
1402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * limitations under the License.
1502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette */
1602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
1702fc5fef36357467eba22a0ee250a96734daf791Alan Viverettepackage android.graphics.drawable;
1802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
1902fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport org.xmlpull.v1.XmlPullParser;
2002fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport org.xmlpull.v1.XmlPullParserException;
2102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
2202fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.annotation.DrawableRes;
2302fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.annotation.NonNull;
2402fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.annotation.Nullable;
2502fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.content.Context;
2602fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.content.res.Resources;
2702fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.content.res.Resources.Theme;
2802fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.util.AttributeSet;
2902fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport android.view.InflateException;
3002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
3102fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport java.io.IOException;
3202fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport java.lang.reflect.Constructor;
3302fc5fef36357467eba22a0ee250a96734daf791Alan Viveretteimport java.util.HashMap;
3402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
3502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette/**
3602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * Instantiates a drawable XML file into its corresponding
3702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * {@link android.graphics.drawable.Drawable} objects.
3802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * <p>
3902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * For performance reasons, inflation relies heavily on pre-processing of
4002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * XML files that is done at build time. Therefore, it is not currently possible
4102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * to use this inflater with an XmlPullParser over a plain XML file at runtime;
4202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * it only works with an XmlPullParser returned from a compiled resource (R.
4302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * <em>something</em> file.)
4402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette *
4502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette * @hide Pending API finalization.
4602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette */
4702fc5fef36357467eba22a0ee250a96734daf791Alan Viverettepublic final class DrawableInflater {
4802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    private static final HashMap<String, Constructor<? extends Drawable>> CONSTRUCTOR_MAP =
4902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            new HashMap<>();
5002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
5102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    private final Resources mRes;
5202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    private final ClassLoader mClassLoader;
5302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
5402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    /**
5502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * Loads the drawable resource with the specified identifier.
5602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     *
5702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param context the context in which the drawable should be loaded
5802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param id the identifier of the drawable resource
5902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @return a drawable, or {@code null} if the drawable failed to load
6002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     */
6102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    @Nullable
6202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    public static Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) {
6302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        return loadDrawable(context.getResources(), context.getTheme(), id);
6402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    }
6502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
6602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    /**
6702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * Loads the drawable resource with the specified identifier.
6802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     *
6902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param resources the resources from which the drawable should be loaded
7002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param theme the theme against which the drawable should be inflated
7102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param id the identifier of the drawable resource
7202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @return a drawable, or {@code null} if the drawable failed to load
7302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     */
7402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    @Nullable
7502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    public static Drawable loadDrawable(
7602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            @NonNull Resources resources, @Nullable Theme theme, @DrawableRes int id) {
7702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        return resources.getDrawable(id, theme);
7802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    }
7902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
8002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    /**
8102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * Constructs a new drawable inflater using the specified resources and
8202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * class loader.
8302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     *
8402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param res the resources used to resolve resource identifiers
8502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param classLoader the class loader used to load custom drawables
8602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @hide
8702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     */
8802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    public DrawableInflater(@NonNull Resources res, @NonNull ClassLoader classLoader) {
8902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        mRes = res;
9002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        mClassLoader = classLoader;
9102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    }
9202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
9302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    /**
9402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * Inflates a drawable from inside an XML document using an optional
9502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * {@link Theme}.
9602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * <p>
9702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * This method should be called on a parser positioned at a tag in an XML
9802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * document defining a drawable resource. It will attempt to create a
9902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * Drawable from the tag at the current position.
10002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     *
10102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param name the name of the tag at the current position
10202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param parser an XML parser positioned at the drawable tag
10302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param attrs an attribute set that wraps the parser
10402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @param theme the theme against which the drawable should be inflated, or
10502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     *              {@code null} to not inflate against a theme
10602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @return a drawable
10702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     *
10802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @throws XmlPullParserException
10902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     * @throws IOException
11002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette     */
11102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    @NonNull
11202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    public Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser,
11302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            @NonNull AttributeSet attrs, @Nullable Theme theme)
11402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            throws XmlPullParserException, IOException {
11550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        return inflateFromXmlForDensity(name, parser, attrs, 0, theme);
11650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    }
11750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski
11850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    /**
11950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski     * Version of {@link #inflateFromXml(String, XmlPullParser, AttributeSet, Theme)} that accepts
12050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski     * an override density.
12150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski     */
12250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    @NonNull
12350954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser,
12450954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            @NonNull AttributeSet attrs, int density, @Nullable Theme theme)
12550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            throws XmlPullParserException, IOException {
126caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette        // Inner classes must be referenced as Outer$Inner, but XML tag names
127caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette        // can't contain $, so the <drawable> tag allows developers to specify
128caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette        // the class in an attribute. We'll still run it through inflateFromTag
129caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette        // to stay consistent with how LayoutInflater works.
130caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette        if (name.equals("drawable")) {
131caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette            name = attrs.getAttributeValue(null, "class");
132caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette            if (name == null) {
133caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette                throw new InflateException("<drawable> tag must specify class attribute");
134caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette            }
135caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette        }
136caca720b176a0dab0a43a20496e676687e8d78f7Alan Viverette
13702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        Drawable drawable = inflateFromTag(name);
13802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        if (drawable == null) {
13902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            drawable = inflateFromClass(name);
14002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        }
14150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        drawable.setSrcDensityOverride(density);
14202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        drawable.inflate(mRes, parser, attrs, theme);
14302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        return drawable;
14402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    }
14502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
14602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    @NonNull
14702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    @SuppressWarnings("deprecation")
14802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    private Drawable inflateFromTag(@NonNull String name) {
14902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        switch (name) {
15002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "selector":
15102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new StateListDrawable();
15202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "animated-selector":
15302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new AnimatedStateListDrawable();
15402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "level-list":
15502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new LevelListDrawable();
15602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "layer-list":
15702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new LayerDrawable();
15802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "transition":
15902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new TransitionDrawable();
16002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "ripple":
16102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new RippleDrawable();
162be8835e86bc39570994af32ead381875e3ee54d5Hyunyoung Song            case "adaptive-icon":
163be8835e86bc39570994af32ead381875e3ee54d5Hyunyoung Song                return new AdaptiveIconDrawable();
16402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "color":
16502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new ColorDrawable();
16602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "shape":
16702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new GradientDrawable();
16802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "vector":
16902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new VectorDrawable();
17002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "animated-vector":
17102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new AnimatedVectorDrawable();
17202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "scale":
17302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new ScaleDrawable();
17402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "clip":
17502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new ClipDrawable();
17602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "rotate":
17702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new RotateDrawable();
17802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "animated-rotate":
17902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new AnimatedRotateDrawable();
18002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "animation-list":
18102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new AnimationDrawable();
18202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "inset":
18302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new InsetDrawable();
18402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "bitmap":
18502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new BitmapDrawable();
18602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            case "nine-patch":
18702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return new NinePatchDrawable();
188127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III            case "animated-image":
189127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III                return new AnimatedImageDrawable();
19002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            default:
19102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                return null;
19202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        }
19302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    }
19402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette
19502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    @NonNull
19602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    private Drawable inflateFromClass(@NonNull String className) {
19702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        try {
19802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            Constructor<? extends Drawable> constructor;
19902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            synchronized (CONSTRUCTOR_MAP) {
20002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                constructor = CONSTRUCTOR_MAP.get(className);
20102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                if (constructor == null) {
20202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                    final Class<? extends Drawable> clazz =
20302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                            mClassLoader.loadClass(className).asSubclass(Drawable.class);
20402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                    constructor = clazz.getConstructor();
20502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                    CONSTRUCTOR_MAP.put(className, constructor);
20602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                }
20702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            }
20802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            return constructor.newInstance();
20902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        } catch (NoSuchMethodException e) {
21002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            final InflateException ie = new InflateException(
21102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                    "Error inflating class " + className);
21202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            ie.initCause(e);
21302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            throw ie;
21402fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        } catch (ClassCastException e) {
21502fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            // If loaded class is not a Drawable subclass.
21602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            final InflateException ie = new InflateException(
21702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                    "Class is not a Drawable " + className);
21802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            ie.initCause(e);
21902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            throw ie;
22002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        } catch (ClassNotFoundException e) {
22102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            // If loadClass fails, we should propagate the exception.
222c725e8d5ea04ffb5821e00db1c6b45cfe2130e05Alan Viverette            final InflateException ie = new InflateException(
223c725e8d5ea04ffb5821e00db1c6b45cfe2130e05Alan Viverette                    "Class not found " + className);
224c725e8d5ea04ffb5821e00db1c6b45cfe2130e05Alan Viverette            ie.initCause(e);
225c725e8d5ea04ffb5821e00db1c6b45cfe2130e05Alan Viverette            throw ie;
22602fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        } catch (Exception e) {
22702fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            final InflateException ie = new InflateException(
22802fc5fef36357467eba22a0ee250a96734daf791Alan Viverette                    "Error inflating class " + className);
22902fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            ie.initCause(e);
23002fc5fef36357467eba22a0ee250a96734daf791Alan Viverette            throw ie;
23102fc5fef36357467eba22a0ee250a96734daf791Alan Viverette        }
23202fc5fef36357467eba22a0ee250a96734daf791Alan Viverette    }
23302fc5fef36357467eba22a0ee250a96734daf791Alan Viverette}
234