1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import com.android.layoutlib.bridge.android.BridgeInflater; 20import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 21 22import org.xmlpull.v1.XmlPullParser; 23import org.xmlpull.v1.XmlPullParserException; 24 25import android.content.res.TypedArray; 26import android.content.res.XmlResourceParser; 27import android.util.AttributeSet; 28import android.util.Xml; 29 30import java.io.IOException; 31 32/** 33 * Delegate used to provide new implementation of a select few methods of {@link LayoutInflater} 34 * 35 * Through the layoutlib_create tool, the original methods of LayoutInflater have been replaced 36 * by calls to methods of the same name in this delegate class. 37 * 38 * Generally we don't want to copy-paste a huge method like that just for one small features, 39 * but because this is done after this platform is final and the next version (Honeycomb) has a 40 * better mechanism (or slightly less copy-paste), maintenance of this duplicated code is not 41 * a problem. 42 * 43 */ 44public class LayoutInflater_Delegate { 45 46 public static boolean sIsInInclude = false; 47 48 @LayoutlibDelegate 49 /*package*/ static void parseInclude(LayoutInflater thisInflater, 50 XmlPullParser parser, View parent, AttributeSet attrs) 51 throws XmlPullParserException, IOException { 52 53 int type; 54 55 if (parent instanceof ViewGroup) { 56 final int layout = attrs.getAttributeResourceValue(null, "layout", 0); 57 if (layout == 0) { 58 final String value = attrs.getAttributeValue(null, "layout"); 59 if (value == null) { 60 throw new InflateException("You must specifiy a layout in the" 61 + " include tag: <include layout=\"@layout/layoutID\" />"); 62 } else { 63 throw new InflateException("You must specifiy a valid layout " 64 + "reference. The layout ID " + value + " is not valid."); 65 } 66 } else { 67 final XmlResourceParser childParser = 68 thisInflater.getContext().getResources().getLayout(layout); 69 70 try { 71 final AttributeSet childAttrs = Xml.asAttributeSet(childParser); 72 73 while ((type = childParser.next()) != XmlPullParser.START_TAG && 74 type != XmlPullParser.END_DOCUMENT) { 75 // Empty. 76 } 77 78 if (type != XmlPullParser.START_TAG) { 79 throw new InflateException(childParser.getPositionDescription() + 80 ": No start tag found!"); 81 } 82 83 final String childName = childParser.getName(); 84 85 if (LayoutInflater.TAG_MERGE.equals(childName)) { 86 // ---- START MODIFICATIONS ---- 87 if (thisInflater instanceof BridgeInflater) { 88 ((BridgeInflater) thisInflater).setIsInMerge(true); 89 } 90 // ---- END MODIFICATIONS ---- 91 92 // Inflate all children. 93 thisInflater.rInflate(childParser, parent, childAttrs); 94 95 // ---- START MODIFICATIONS ---- 96 if (thisInflater instanceof BridgeInflater) { 97 ((BridgeInflater) thisInflater).setIsInMerge(false); 98 } 99 // ---- END MODIFICATIONS ---- 100 } else { 101 final View view = thisInflater.createViewFromTag(childName, childAttrs); 102 final ViewGroup group = (ViewGroup) parent; 103 104 // We try to load the layout params set in the <include /> tag. If 105 // they don't exist, we will rely on the layout params set in the 106 // included XML file. 107 // During a layoutparams generation, a runtime exception is thrown 108 // if either layout_width or layout_height is missing. We catch 109 // this exception and set localParams accordingly: true means we 110 // successfully loaded layout params from the <include /> tag, 111 // false means we need to rely on the included layout params. 112 ViewGroup.LayoutParams params = null; 113 try { 114 // ---- START CHANGES 115 sIsInInclude = true; 116 // ---- END CHANGES 117 118 params = group.generateLayoutParams(attrs); 119 } catch (RuntimeException e) { 120 // ---- START CHANGES 121 sIsInInclude = false; 122 // ---- END CHANGES 123 124 params = group.generateLayoutParams(childAttrs); 125 } finally { 126 // ---- START CHANGES 127 sIsInInclude = false; 128 // ---- END CHANGES 129 130 if (params != null) { 131 view.setLayoutParams(params); 132 } 133 } 134 135 // Inflate all children. 136 thisInflater.rInflate(childParser, view, childAttrs); 137 138 // Attempt to override the included layout's android:id with the 139 // one set on the <include /> tag itself. 140 TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs, 141 com.android.internal.R.styleable.View, 0, 0); 142 int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID); 143 // While we're at it, let's try to override android:visibility. 144 int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1); 145 a.recycle(); 146 147 if (id != View.NO_ID) { 148 view.setId(id); 149 } 150 151 switch (visibility) { 152 case 0: 153 view.setVisibility(View.VISIBLE); 154 break; 155 case 1: 156 view.setVisibility(View.INVISIBLE); 157 break; 158 case 2: 159 view.setVisibility(View.GONE); 160 break; 161 } 162 163 group.addView(view); 164 } 165 } finally { 166 childParser.close(); 167 } 168 } 169 } else { 170 throw new InflateException("<include /> can only be used inside of a ViewGroup"); 171 } 172 173 final int currentDepth = parser.getDepth(); 174 while (((type = parser.next()) != XmlPullParser.END_TAG || 175 parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) { 176 // Empty 177 } 178 } 179} 180