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