1 /* 2 * Copyright (C) 2008 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 com.android.layoutlib.bridge.android; 18 19 20 import com.android.ide.common.rendering.api.ILayoutPullParser; 21 import com.android.layoutlib.bridge.impl.ParserFactory; 22 23 import org.xmlpull.v1.XmlPullParser; 24 import org.xmlpull.v1.XmlPullParserException; 25 26 import android.content.res.XmlResourceParser; 27 import android.util.AttributeSet; 28 import android.util.BridgeXmlPullAttributes; 29 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.Reader; 33 34 /** 35 * {@link BridgeXmlBlockParser} reimplements most of android.xml.XmlBlock.Parser. 36 * It delegates to both an instance of {@link XmlPullParser} and an instance of 37 * XmlPullAttributes (for the {@link AttributeSet} part). 38 */ 39 public class BridgeXmlBlockParser implements XmlResourceParser { 40 41 private final XmlPullParser mParser; 42 private final BridgeXmlPullAttributes mAttrib; 43 private final BridgeContext mContext; 44 private final boolean mPlatformFile; 45 46 private boolean mStarted = false; 47 private int mEventType = START_DOCUMENT; 48 49 private boolean mPopped = true; // default to true in case it's not pushed. 50 51 /** 52 * Builds a {@link BridgeXmlBlockParser}. 53 * @param parser The XmlPullParser to get the content from. 54 * @param context the Context. 55 * @param platformFile Indicates whether the the file is a platform file or not. 56 */ 57 public BridgeXmlBlockParser(XmlPullParser parser, BridgeContext context, boolean platformFile) { 58 if (ParserFactory.LOG_PARSER) { 59 System.out.println("CRTE " + parser.toString()); 60 } 61 62 mParser = parser; 63 mContext = context; 64 mPlatformFile = platformFile; 65 mAttrib = new BridgeXmlPullAttributes(parser, context, mPlatformFile); 66 67 if (mContext != null) { 68 mContext.pushParser(this); 69 mPopped = false; 70 } 71 } 72 73 public XmlPullParser getParser() { 74 return mParser; 75 } 76 77 public boolean isPlatformFile() { 78 return mPlatformFile; 79 } 80 81 public Object getViewCookie() { 82 if (mParser instanceof ILayoutPullParser) { 83 return ((ILayoutPullParser)mParser).getViewCookie(); 84 } 85 86 return null; 87 } 88 89 public void ensurePopped() { 90 if (mContext != null && mPopped == false) { 91 mContext.popParser(); 92 mPopped = true; 93 } 94 } 95 96 // ------- XmlResourceParser implementation 97 98 public void setFeature(String name, boolean state) 99 throws XmlPullParserException { 100 if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) { 101 return; 102 } 103 if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) { 104 return; 105 } 106 throw new XmlPullParserException("Unsupported feature: " + name); 107 } 108 109 public boolean getFeature(String name) { 110 if (FEATURE_PROCESS_NAMESPACES.equals(name)) { 111 return true; 112 } 113 if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { 114 return true; 115 } 116 return false; 117 } 118 119 public void setProperty(String name, Object value) throws XmlPullParserException { 120 throw new XmlPullParserException("setProperty() not supported"); 121 } 122 123 public Object getProperty(String name) { 124 return null; 125 } 126 127 public void setInput(Reader in) throws XmlPullParserException { 128 mParser.setInput(in); 129 } 130 131 public void setInput(InputStream inputStream, String inputEncoding) 132 throws XmlPullParserException { 133 mParser.setInput(inputStream, inputEncoding); 134 } 135 136 public void defineEntityReplacementText(String entityName, 137 String replacementText) throws XmlPullParserException { 138 throw new XmlPullParserException( 139 "defineEntityReplacementText() not supported"); 140 } 141 142 public String getNamespacePrefix(int pos) throws XmlPullParserException { 143 throw new XmlPullParserException("getNamespacePrefix() not supported"); 144 } 145 146 public String getInputEncoding() { 147 return null; 148 } 149 150 public String getNamespace(String prefix) { 151 throw new RuntimeException("getNamespace() not supported"); 152 } 153 154 public int getNamespaceCount(int depth) throws XmlPullParserException { 155 throw new XmlPullParserException("getNamespaceCount() not supported"); 156 } 157 158 public String getPositionDescription() { 159 return "Binary XML file line #" + getLineNumber(); 160 } 161 162 public String getNamespaceUri(int pos) throws XmlPullParserException { 163 throw new XmlPullParserException("getNamespaceUri() not supported"); 164 } 165 166 public int getColumnNumber() { 167 return -1; 168 } 169 170 public int getDepth() { 171 return mParser.getDepth(); 172 } 173 174 public String getText() { 175 return mParser.getText(); 176 } 177 178 public int getLineNumber() { 179 return mParser.getLineNumber(); 180 } 181 182 public int getEventType() { 183 return mEventType; 184 } 185 186 public boolean isWhitespace() throws XmlPullParserException { 187 // Original comment: whitespace was stripped by aapt. 188 return mParser.isWhitespace(); 189 } 190 191 public String getPrefix() { 192 throw new RuntimeException("getPrefix not supported"); 193 } 194 195 public char[] getTextCharacters(int[] holderForStartAndLength) { 196 String txt = getText(); 197 char[] chars = null; 198 if (txt != null) { 199 holderForStartAndLength[0] = 0; 200 holderForStartAndLength[1] = txt.length(); 201 chars = new char[txt.length()]; 202 txt.getChars(0, txt.length(), chars, 0); 203 } 204 return chars; 205 } 206 207 public String getNamespace() { 208 return mParser.getNamespace(); 209 } 210 211 public String getName() { 212 return mParser.getName(); 213 } 214 215 public String getAttributeNamespace(int index) { 216 return mParser.getAttributeNamespace(index); 217 } 218 219 public String getAttributeName(int index) { 220 return mParser.getAttributeName(index); 221 } 222 223 public String getAttributePrefix(int index) { 224 throw new RuntimeException("getAttributePrefix not supported"); 225 } 226 227 public boolean isEmptyElementTag() { 228 // XXX Need to detect this. 229 return false; 230 } 231 232 public int getAttributeCount() { 233 return mParser.getAttributeCount(); 234 } 235 236 public String getAttributeValue(int index) { 237 return mParser.getAttributeValue(index); 238 } 239 240 public String getAttributeType(int index) { 241 return "CDATA"; 242 } 243 244 public boolean isAttributeDefault(int index) { 245 return false; 246 } 247 248 public int nextToken() throws XmlPullParserException, IOException { 249 return next(); 250 } 251 252 public String getAttributeValue(String namespace, String name) { 253 return mParser.getAttributeValue(namespace, name); 254 } 255 256 public int next() throws XmlPullParserException, IOException { 257 if (!mStarted) { 258 mStarted = true; 259 260 if (ParserFactory.LOG_PARSER) { 261 System.out.println("STRT " + mParser.toString()); 262 } 263 264 return START_DOCUMENT; 265 } 266 267 int ev = mParser.next(); 268 269 if (ParserFactory.LOG_PARSER) { 270 System.out.println("NEXT " + mParser.toString() + " " + 271 eventTypeToString(mEventType) + " -> " + eventTypeToString(ev)); 272 } 273 274 if (ev == END_TAG && mParser.getDepth() == 1) { 275 // done with parser remove it from the context stack. 276 ensurePopped(); 277 278 if (ParserFactory.LOG_PARSER) { 279 System.out.println(""); 280 } 281 } 282 283 mEventType = ev; 284 return ev; 285 } 286 287 public static String eventTypeToString(int eventType) { 288 switch (eventType) { 289 case START_DOCUMENT: 290 return "START_DOC"; 291 case END_DOCUMENT: 292 return "END_DOC"; 293 case START_TAG: 294 return "START_TAG"; 295 case END_TAG: 296 return "END_TAG"; 297 case TEXT: 298 return "TEXT"; 299 case CDSECT: 300 return "CDSECT"; 301 case ENTITY_REF: 302 return "ENTITY_REF"; 303 case IGNORABLE_WHITESPACE: 304 return "IGNORABLE_WHITESPACE"; 305 case PROCESSING_INSTRUCTION: 306 return "PROCESSING_INSTRUCTION"; 307 case COMMENT: 308 return "COMMENT"; 309 case DOCDECL: 310 return "DOCDECL"; 311 } 312 313 return "????"; 314 } 315 316 public void require(int type, String namespace, String name) 317 throws XmlPullParserException { 318 if (type != getEventType() 319 || (namespace != null && !namespace.equals(getNamespace())) 320 || (name != null && !name.equals(getName()))) 321 throw new XmlPullParserException("expected " + TYPES[type] 322 + getPositionDescription()); 323 } 324 325 public String nextText() throws XmlPullParserException, IOException { 326 if (getEventType() != START_TAG) { 327 throw new XmlPullParserException(getPositionDescription() 328 + ": parser must be on START_TAG to read next text", this, 329 null); 330 } 331 int eventType = next(); 332 if (eventType == TEXT) { 333 String result = getText(); 334 eventType = next(); 335 if (eventType != END_TAG) { 336 throw new XmlPullParserException( 337 getPositionDescription() 338 + ": event TEXT it must be immediately followed by END_TAG", 339 this, null); 340 } 341 return result; 342 } else if (eventType == END_TAG) { 343 return ""; 344 } else { 345 throw new XmlPullParserException(getPositionDescription() 346 + ": parser must be on START_TAG or TEXT to read text", 347 this, null); 348 } 349 } 350 351 public int nextTag() throws XmlPullParserException, IOException { 352 int eventType = next(); 353 if (eventType == TEXT && isWhitespace()) { // skip whitespace 354 eventType = next(); 355 } 356 if (eventType != START_TAG && eventType != END_TAG) { 357 throw new XmlPullParserException(getPositionDescription() 358 + ": expected start or end tag", this, null); 359 } 360 return eventType; 361 } 362 363 // AttributeSet implementation 364 365 366 public void close() { 367 // pass 368 } 369 370 public boolean getAttributeBooleanValue(int index, boolean defaultValue) { 371 return mAttrib.getAttributeBooleanValue(index, defaultValue); 372 } 373 374 public boolean getAttributeBooleanValue(String namespace, String attribute, 375 boolean defaultValue) { 376 return mAttrib.getAttributeBooleanValue(namespace, attribute, defaultValue); 377 } 378 379 public float getAttributeFloatValue(int index, float defaultValue) { 380 return mAttrib.getAttributeFloatValue(index, defaultValue); 381 } 382 383 public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) { 384 return mAttrib.getAttributeFloatValue(namespace, attribute, defaultValue); 385 } 386 387 public int getAttributeIntValue(int index, int defaultValue) { 388 return mAttrib.getAttributeIntValue(index, defaultValue); 389 } 390 391 public int getAttributeIntValue(String namespace, String attribute, int defaultValue) { 392 return mAttrib.getAttributeIntValue(namespace, attribute, defaultValue); 393 } 394 395 public int getAttributeListValue(int index, String[] options, int defaultValue) { 396 return mAttrib.getAttributeListValue(index, options, defaultValue); 397 } 398 399 public int getAttributeListValue(String namespace, String attribute, 400 String[] options, int defaultValue) { 401 return mAttrib.getAttributeListValue(namespace, attribute, options, defaultValue); 402 } 403 404 public int getAttributeNameResource(int index) { 405 return mAttrib.getAttributeNameResource(index); 406 } 407 408 public int getAttributeResourceValue(int index, int defaultValue) { 409 return mAttrib.getAttributeResourceValue(index, defaultValue); 410 } 411 412 public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) { 413 return mAttrib.getAttributeResourceValue(namespace, attribute, defaultValue); 414 } 415 416 public int getAttributeUnsignedIntValue(int index, int defaultValue) { 417 return mAttrib.getAttributeUnsignedIntValue(index, defaultValue); 418 } 419 420 public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) { 421 return mAttrib.getAttributeUnsignedIntValue(namespace, attribute, defaultValue); 422 } 423 424 public String getClassAttribute() { 425 return mAttrib.getClassAttribute(); 426 } 427 428 public String getIdAttribute() { 429 return mAttrib.getIdAttribute(); 430 } 431 432 public int getIdAttributeResourceValue(int defaultValue) { 433 return mAttrib.getIdAttributeResourceValue(defaultValue); 434 } 435 436 public int getStyleAttribute() { 437 return mAttrib.getStyleAttribute(); 438 } 439 } 440