182b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet/*
282b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * Copyright (C) 2011 The Android Open Source Project
382b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet *
482b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
582b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * you may not use this file except in compliance with the License.
682b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * You may obtain a copy of the License at
782b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet *
882b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
982b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet *
1082b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
1182b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
1282b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1382b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * See the License for the specific language governing permissions and
1482b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * limitations under the License.
1582b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet */
1682b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
1782b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohetpackage android.view;
1882b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
199a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohetimport com.android.tools.layoutlib.annotations.LayoutlibDelegate;
2082b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
2182b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohetimport org.xmlpull.v1.XmlPullParser;
2282b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohetimport org.xmlpull.v1.XmlPullParserException;
2382b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
24fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohetimport android.content.res.TypedArray;
25fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohetimport android.content.res.XmlResourceParser;
2682b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohetimport android.util.AttributeSet;
27fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohetimport android.util.Xml;
2882b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
2982b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohetimport java.io.IOException;
3082b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
3182b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet/**
3282b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * Delegate used to provide new implementation of a select few methods of {@link LayoutInflater}
3382b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet *
3482b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * Through the layoutlib_create tool, the original  methods of LayoutInflater have been replaced
3582b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet * by calls to methods of the same name in this delegate class.
3682b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet *
3782b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet */
3882b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohetpublic class LayoutInflater_Delegate {
3982b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
40d2f664d42cc29507b01a98622298b69131463825Xavier Ducrohet    private static final String TAG_MERGE = "merge";
41d2f664d42cc29507b01a98622298b69131463825Xavier Ducrohet
42fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet    public static boolean sIsInInclude = false;
43fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
4482b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet    /**
4582b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet     * Recursive method used to descend down the xml hierarchy and instantiate
4682b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet     * views, instantiate their children, and then call onFinishInflate().
47d2f664d42cc29507b01a98622298b69131463825Xavier Ducrohet     *
48d2f664d42cc29507b01a98622298b69131463825Xavier Ducrohet     * This implementation just records the merge status before calling the default implementation.
4982b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet     */
509a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
5182b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet    /*package*/ static void rInflate(LayoutInflater thisInflater,
5282b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            XmlPullParser parser, View parent, final AttributeSet attrs,
5382b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            boolean finishInflate) throws XmlPullParserException, IOException {
5482b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
5582b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet        if (finishInflate == false) {
5682b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            // this is a merge rInflate!
5782b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            if (thisInflater instanceof BridgeInflater) {
5882b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet                ((BridgeInflater) thisInflater).setIsInMerge(true);
5982b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            }
6082b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet        }
6182b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
6282b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet        // ---- START DEFAULT IMPLEMENTATION.
6382b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
64d2f664d42cc29507b01a98622298b69131463825Xavier Ducrohet        thisInflater.rInflate_Original(parser, parent, attrs, finishInflate);
6582b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
6682b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet        // ---- END DEFAULT IMPLEMENTATION.
6782b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet
6882b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet        if (finishInflate == false) {
6982b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            // this is a merge rInflate!
7082b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            if (thisInflater instanceof BridgeInflater) {
7182b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet                ((BridgeInflater) thisInflater).setIsInMerge(false);
7282b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet            }
7382b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet        }
7482b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet    }
75fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
76fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet    @LayoutlibDelegate
77fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet    public static void parseInclude(
78fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            LayoutInflater thisInflater,
79fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            XmlPullParser parser, View parent, AttributeSet attrs)
80fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            throws XmlPullParserException, IOException {
81fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
82fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        int type;
83fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
84fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        if (parent instanceof ViewGroup) {
85fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
86fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            if (layout == 0) {
87fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                final String value = attrs.getAttributeValue(null, "layout");
88fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                if (value == null) {
89fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    throw new InflateException("You must specifiy a layout in the"
90fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            + " include tag: <include layout=\"@layout/layoutID\" />");
91fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                } else {
92fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    throw new InflateException("You must specifiy a valid layout "
93fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            + "reference. The layout ID " + value + " is not valid.");
94fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                }
95fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            } else {
96fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                final XmlResourceParser childParser =
97fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    thisInflater.getContext().getResources().getLayout(layout);
98fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
99fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                try {
100fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
101fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
102fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    while ((type = childParser.next()) != XmlPullParser.START_TAG &&
103fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            type != XmlPullParser.END_DOCUMENT) {
104fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // Empty.
105fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    }
106fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
107fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    if (type != XmlPullParser.START_TAG) {
108fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        throw new InflateException(childParser.getPositionDescription() +
109fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                ": No start tag found!");
110fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    }
111fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
112fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    final String childName = childParser.getName();
113fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
114d2f664d42cc29507b01a98622298b69131463825Xavier Ducrohet                    if (TAG_MERGE.equals(childName)) {
115fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // Inflate all children.
116fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        thisInflater.rInflate(childParser, parent, childAttrs, false);
117fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    } else {
118fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        final View view = thisInflater.createViewFromTag(parent, childName, childAttrs);
119fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        final ViewGroup group = (ViewGroup) parent;
120fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
121fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // We try to load the layout params set in the <include /> tag. If
122fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // they don't exist, we will rely on the layout params set in the
123fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // included XML file.
124fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // During a layoutparams generation, a runtime exception is thrown
125fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // if either layout_width or layout_height is missing. We catch
126fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // this exception and set localParams accordingly: true means we
127fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // successfully loaded layout params from the <include /> tag,
128fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // false means we need to rely on the included layout params.
129fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        ViewGroup.LayoutParams params = null;
130fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        try {
131fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            // ---- START CHANGES
132fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            sIsInInclude = true;
133fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            // ---- END CHANGES
134fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
135fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            params = group.generateLayoutParams(attrs);
136fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
137fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        } catch (RuntimeException e) {
138fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            // ---- START CHANGES
139fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            sIsInInclude = false;
140fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            // ---- END CHANGES
141fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
142fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            params = group.generateLayoutParams(childAttrs);
143fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        } finally {
144fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            // ---- START CHANGES
145fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            sIsInInclude = false;
146fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            // ---- END CHANGES
147fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
148fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            if (params != null) {
149fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                view.setLayoutParams(params);
150fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            }
151fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        }
152fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
153fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // Inflate all children.
154fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        thisInflater.rInflate(childParser, view, childAttrs, true);
155fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
156fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // Attempt to override the included layout's android:id with the
157fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // one set on the <include /> tag itself.
158fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs,
159fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            com.android.internal.R.styleable.View, 0, 0);
160fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
161fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        // While we're at it, let's try to override android:visibility.
162fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
163fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        a.recycle();
164fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
165fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        if (id != View.NO_ID) {
166fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            view.setId(id);
167fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        }
168fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
169fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        switch (visibility) {
170fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            case 0:
171fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                view.setVisibility(View.VISIBLE);
172fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                break;
173fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            case 1:
174fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                view.setVisibility(View.INVISIBLE);
175fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                break;
176fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                            case 2:
177fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                view.setVisibility(View.GONE);
178fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                                break;
179fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        }
180fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
181fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                        group.addView(view);
182fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    }
183fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                } finally {
184fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                    childParser.close();
185fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                }
186fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            }
187fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        } else {
188fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            throw new InflateException("<include /> can only be used inside of a ViewGroup");
189fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        }
190fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
191fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        final int currentDepth = parser.getDepth();
192fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        while (((type = parser.next()) != XmlPullParser.END_TAG ||
193fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet                parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
194fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet            // Empty
195fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        }
196fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet    }
197fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
198fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
19982b9232565bfececdb643a94cecdd1bd1cb5c643Xavier Ducrohet}
200