Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 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 | |
| 17 | package android.view; |
| 18 | |
Xavier Ducrohet | 9a4fe29 | 2011-02-09 17:17:49 -0800 | [diff] [blame] | 19 | import com.android.tools.layoutlib.annotations.LayoutlibDelegate; |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 20 | |
| 21 | import org.xmlpull.v1.XmlPullParser; |
| 22 | import org.xmlpull.v1.XmlPullParserException; |
| 23 | |
Xavier Ducrohet | fb93ce9 | 2011-06-03 19:38:03 -0700 | [diff] [blame] | 24 | import android.content.res.TypedArray; |
| 25 | import android.content.res.XmlResourceParser; |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 26 | import android.util.AttributeSet; |
Xavier Ducrohet | fb93ce9 | 2011-06-03 19:38:03 -0700 | [diff] [blame] | 27 | import android.util.Xml; |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 28 | |
| 29 | import java.io.IOException; |
| 30 | |
| 31 | /** |
| 32 | * Delegate used to provide new implementation of a select few methods of {@link LayoutInflater} |
| 33 | * |
| 34 | * Through the layoutlib_create tool, the original methods of LayoutInflater have been replaced |
| 35 | * by calls to methods of the same name in this delegate class. |
| 36 | * |
| 37 | */ |
| 38 | public class LayoutInflater_Delegate { |
| 39 | |
Xavier Ducrohet | d2f664d | 2011-07-29 17:41:39 -0700 | [diff] [blame] | 40 | private static final String TAG_MERGE = "merge"; |
| 41 | |
Xavier Ducrohet | fb93ce9 | 2011-06-03 19:38:03 -0700 | [diff] [blame] | 42 | public static boolean sIsInInclude = false; |
| 43 | |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 44 | /** |
| 45 | * Recursive method used to descend down the xml hierarchy and instantiate |
| 46 | * views, instantiate their children, and then call onFinishInflate(). |
Xavier Ducrohet | d2f664d | 2011-07-29 17:41:39 -0700 | [diff] [blame] | 47 | * |
| 48 | * This implementation just records the merge status before calling the default implementation. |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 49 | */ |
Xavier Ducrohet | 9a4fe29 | 2011-02-09 17:17:49 -0800 | [diff] [blame] | 50 | @LayoutlibDelegate |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 51 | /*package*/ static void rInflate(LayoutInflater thisInflater, |
| 52 | XmlPullParser parser, View parent, final AttributeSet attrs, |
| 53 | boolean finishInflate) throws XmlPullParserException, IOException { |
| 54 | |
| 55 | if (finishInflate == false) { |
| 56 | // this is a merge rInflate! |
| 57 | if (thisInflater instanceof BridgeInflater) { |
| 58 | ((BridgeInflater) thisInflater).setIsInMerge(true); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | // ---- START DEFAULT IMPLEMENTATION. |
| 63 | |
Xavier Ducrohet | d2f664d | 2011-07-29 17:41:39 -0700 | [diff] [blame] | 64 | thisInflater.rInflate_Original(parser, parent, attrs, finishInflate); |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 65 | |
| 66 | // ---- END DEFAULT IMPLEMENTATION. |
| 67 | |
| 68 | if (finishInflate == false) { |
| 69 | // this is a merge rInflate! |
| 70 | if (thisInflater instanceof BridgeInflater) { |
| 71 | ((BridgeInflater) thisInflater).setIsInMerge(false); |
| 72 | } |
| 73 | } |
| 74 | } |
Xavier Ducrohet | fb93ce9 | 2011-06-03 19:38:03 -0700 | [diff] [blame] | 75 | |
| 76 | @LayoutlibDelegate |
| 77 | public static void parseInclude( |
| 78 | LayoutInflater thisInflater, |
| 79 | XmlPullParser parser, View parent, AttributeSet attrs) |
| 80 | throws XmlPullParserException, IOException { |
| 81 | |
| 82 | int type; |
| 83 | |
| 84 | if (parent instanceof ViewGroup) { |
| 85 | final int layout = attrs.getAttributeResourceValue(null, "layout", 0); |
| 86 | if (layout == 0) { |
| 87 | final String value = attrs.getAttributeValue(null, "layout"); |
| 88 | if (value == null) { |
| 89 | throw new InflateException("You must specifiy a layout in the" |
| 90 | + " include tag: <include layout=\"@layout/layoutID\" />"); |
| 91 | } else { |
| 92 | throw new InflateException("You must specifiy a valid layout " |
| 93 | + "reference. The layout ID " + value + " is not valid."); |
| 94 | } |
| 95 | } else { |
| 96 | final XmlResourceParser childParser = |
| 97 | thisInflater.getContext().getResources().getLayout(layout); |
| 98 | |
| 99 | try { |
| 100 | final AttributeSet childAttrs = Xml.asAttributeSet(childParser); |
| 101 | |
| 102 | while ((type = childParser.next()) != XmlPullParser.START_TAG && |
| 103 | type != XmlPullParser.END_DOCUMENT) { |
| 104 | // Empty. |
| 105 | } |
| 106 | |
| 107 | if (type != XmlPullParser.START_TAG) { |
| 108 | throw new InflateException(childParser.getPositionDescription() + |
| 109 | ": No start tag found!"); |
| 110 | } |
| 111 | |
| 112 | final String childName = childParser.getName(); |
| 113 | |
Xavier Ducrohet | d2f664d | 2011-07-29 17:41:39 -0700 | [diff] [blame] | 114 | if (TAG_MERGE.equals(childName)) { |
Xavier Ducrohet | fb93ce9 | 2011-06-03 19:38:03 -0700 | [diff] [blame] | 115 | // Inflate all children. |
| 116 | thisInflater.rInflate(childParser, parent, childAttrs, false); |
| 117 | } else { |
| 118 | final View view = thisInflater.createViewFromTag(parent, childName, childAttrs); |
| 119 | final ViewGroup group = (ViewGroup) parent; |
| 120 | |
| 121 | // We try to load the layout params set in the <include /> tag. If |
| 122 | // they don't exist, we will rely on the layout params set in the |
| 123 | // included XML file. |
| 124 | // During a layoutparams generation, a runtime exception is thrown |
| 125 | // if either layout_width or layout_height is missing. We catch |
| 126 | // this exception and set localParams accordingly: true means we |
| 127 | // successfully loaded layout params from the <include /> tag, |
| 128 | // false means we need to rely on the included layout params. |
| 129 | ViewGroup.LayoutParams params = null; |
| 130 | try { |
| 131 | // ---- START CHANGES |
| 132 | sIsInInclude = true; |
| 133 | // ---- END CHANGES |
| 134 | |
| 135 | params = group.generateLayoutParams(attrs); |
| 136 | |
| 137 | } catch (RuntimeException e) { |
| 138 | // ---- START CHANGES |
| 139 | sIsInInclude = false; |
| 140 | // ---- END CHANGES |
| 141 | |
| 142 | params = group.generateLayoutParams(childAttrs); |
| 143 | } finally { |
| 144 | // ---- START CHANGES |
| 145 | sIsInInclude = false; |
| 146 | // ---- END CHANGES |
| 147 | |
| 148 | if (params != null) { |
| 149 | view.setLayoutParams(params); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | // Inflate all children. |
| 154 | thisInflater.rInflate(childParser, view, childAttrs, true); |
| 155 | |
| 156 | // Attempt to override the included layout's android:id with the |
| 157 | // one set on the <include /> tag itself. |
| 158 | TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs, |
| 159 | com.android.internal.R.styleable.View, 0, 0); |
| 160 | int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID); |
| 161 | // While we're at it, let's try to override android:visibility. |
| 162 | int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1); |
| 163 | a.recycle(); |
| 164 | |
| 165 | if (id != View.NO_ID) { |
| 166 | view.setId(id); |
| 167 | } |
| 168 | |
| 169 | switch (visibility) { |
| 170 | case 0: |
| 171 | view.setVisibility(View.VISIBLE); |
| 172 | break; |
| 173 | case 1: |
| 174 | view.setVisibility(View.INVISIBLE); |
| 175 | break; |
| 176 | case 2: |
| 177 | view.setVisibility(View.GONE); |
| 178 | break; |
| 179 | } |
| 180 | |
| 181 | group.addView(view); |
| 182 | } |
| 183 | } finally { |
| 184 | childParser.close(); |
| 185 | } |
| 186 | } |
| 187 | } else { |
| 188 | throw new InflateException("<include /> can only be used inside of a ViewGroup"); |
| 189 | } |
| 190 | |
| 191 | final int currentDepth = parser.getDepth(); |
| 192 | while (((type = parser.next()) != XmlPullParser.END_TAG || |
| 193 | parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) { |
| 194 | // Empty |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | |
Xavier Ducrohet | 82b9232 | 2011-01-24 14:03:21 -0800 | [diff] [blame] | 199 | } |