| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.layoutlib.bridge.android; |
| |
| |
| import com.android.ide.common.rendering.api.ILayoutPullParser; |
| import com.android.layoutlib.bridge.impl.ParserFactory; |
| |
| import org.xmlpull.v1.XmlPullParser; |
| import org.xmlpull.v1.XmlPullParserException; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.content.res.XmlResourceParser; |
| import android.util.AttributeSet; |
| import android.util.BridgeXmlPullAttributes; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| |
| /** |
| * {@link BridgeXmlBlockParser} reimplements most of android.xml.XmlBlock.Parser. |
| * It delegates to both an instance of {@link XmlPullParser} and an instance of |
| * XmlPullAttributes (for the {@link AttributeSet} part). |
| */ |
| public class BridgeXmlBlockParser implements XmlResourceParser { |
| |
| private final XmlPullParser mParser; |
| private final AttributeSet mAttrib; |
| private final BridgeContext mContext; |
| private final boolean mPlatformFile; |
| |
| private boolean mStarted = false; |
| private int mEventType = START_DOCUMENT; |
| |
| private boolean mPopped = true; // default to true in case it's not pushed. |
| |
| /** |
| * Builds a {@link BridgeXmlBlockParser}. |
| * @param parser The XmlPullParser to get the content from. |
| * @param context the Context. |
| * @param platformFile Indicates whether the the file is a platform file or not. |
| */ |
| public BridgeXmlBlockParser(@NonNull XmlPullParser parser, @Nullable BridgeContext context, |
| boolean platformFile) { |
| if (ParserFactory.LOG_PARSER) { |
| System.out.println("CRTE " + parser.toString()); |
| } |
| |
| mParser = parser; |
| mContext = context; |
| mPlatformFile = platformFile; |
| |
| if (mContext != null) { |
| mAttrib = new BridgeXmlPullAttributes(parser, context, mPlatformFile); |
| mContext.pushParser(this); |
| mPopped = false; |
| } |
| else { |
| mAttrib = new NopAttributeSet(); |
| } |
| } |
| |
| public XmlPullParser getParser() { |
| return mParser; |
| } |
| |
| public boolean isPlatformFile() { |
| return mPlatformFile; |
| } |
| |
| public Object getViewCookie() { |
| if (mParser instanceof ILayoutPullParser) { |
| return ((ILayoutPullParser)mParser).getViewCookie(); |
| } |
| |
| return null; |
| } |
| |
| public void ensurePopped() { |
| if (mContext != null && !mPopped) { |
| mContext.popParser(); |
| mPopped = true; |
| } |
| } |
| |
| // ------- XmlResourceParser implementation |
| |
| @Override |
| public void setFeature(String name, boolean state) |
| throws XmlPullParserException { |
| if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) { |
| return; |
| } |
| if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) { |
| return; |
| } |
| throw new XmlPullParserException("Unsupported feature: " + name); |
| } |
| |
| @Override |
| public boolean getFeature(String name) { |
| return FEATURE_PROCESS_NAMESPACES.equals(name) || |
| FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name); |
| } |
| |
| @Override |
| public void setProperty(String name, Object value) throws XmlPullParserException { |
| throw new XmlPullParserException("setProperty() not supported"); |
| } |
| |
| @Override |
| public Object getProperty(String name) { |
| return null; |
| } |
| |
| @Override |
| public void setInput(Reader in) throws XmlPullParserException { |
| mParser.setInput(in); |
| } |
| |
| @Override |
| public void setInput(InputStream inputStream, String inputEncoding) |
| throws XmlPullParserException { |
| mParser.setInput(inputStream, inputEncoding); |
| } |
| |
| @Override |
| public void defineEntityReplacementText(String entityName, |
| String replacementText) throws XmlPullParserException { |
| throw new XmlPullParserException( |
| "defineEntityReplacementText() not supported"); |
| } |
| |
| @Override |
| public String getNamespacePrefix(int pos) throws XmlPullParserException { |
| throw new XmlPullParserException("getNamespacePrefix() not supported"); |
| } |
| |
| @Override |
| public String getInputEncoding() { |
| return null; |
| } |
| |
| @Override |
| public String getNamespace(String prefix) { |
| throw new RuntimeException("getNamespace() not supported"); |
| } |
| |
| @Override |
| public int getNamespaceCount(int depth) throws XmlPullParserException { |
| throw new XmlPullParserException("getNamespaceCount() not supported"); |
| } |
| |
| @Override |
| public String getPositionDescription() { |
| return "Binary XML file line #" + getLineNumber(); |
| } |
| |
| @Override |
| public String getNamespaceUri(int pos) throws XmlPullParserException { |
| throw new XmlPullParserException("getNamespaceUri() not supported"); |
| } |
| |
| @Override |
| public int getColumnNumber() { |
| return -1; |
| } |
| |
| @Override |
| public int getDepth() { |
| return mParser.getDepth(); |
| } |
| |
| @Override |
| public String getText() { |
| return mParser.getText(); |
| } |
| |
| @Override |
| public int getLineNumber() { |
| return mParser.getLineNumber(); |
| } |
| |
| @Override |
| public int getEventType() { |
| return mEventType; |
| } |
| |
| @Override |
| public boolean isWhitespace() throws XmlPullParserException { |
| // Original comment: whitespace was stripped by aapt. |
| return mParser.isWhitespace(); |
| } |
| |
| @Override |
| public String getPrefix() { |
| throw new RuntimeException("getPrefix not supported"); |
| } |
| |
| @Override |
| public char[] getTextCharacters(int[] holderForStartAndLength) { |
| String txt = getText(); |
| char[] chars = null; |
| if (txt != null) { |
| holderForStartAndLength[0] = 0; |
| holderForStartAndLength[1] = txt.length(); |
| chars = new char[txt.length()]; |
| txt.getChars(0, txt.length(), chars, 0); |
| } |
| return chars; |
| } |
| |
| @Override |
| public String getNamespace() { |
| return mParser.getNamespace(); |
| } |
| |
| @Override |
| public String getName() { |
| return mParser.getName(); |
| } |
| |
| @Override |
| public String getAttributeNamespace(int index) { |
| return mParser.getAttributeNamespace(index); |
| } |
| |
| @Override |
| public String getAttributeName(int index) { |
| return mParser.getAttributeName(index); |
| } |
| |
| @Override |
| public String getAttributePrefix(int index) { |
| throw new RuntimeException("getAttributePrefix not supported"); |
| } |
| |
| @Override |
| public boolean isEmptyElementTag() { |
| // XXX Need to detect this. |
| return false; |
| } |
| |
| @Override |
| public int getAttributeCount() { |
| return mParser.getAttributeCount(); |
| } |
| |
| @Override |
| public String getAttributeValue(int index) { |
| return mParser.getAttributeValue(index); |
| } |
| |
| @Override |
| public String getAttributeType(int index) { |
| return "CDATA"; |
| } |
| |
| @Override |
| public boolean isAttributeDefault(int index) { |
| return false; |
| } |
| |
| @Override |
| public int nextToken() throws XmlPullParserException, IOException { |
| return next(); |
| } |
| |
| @Override |
| public String getAttributeValue(String namespace, String name) { |
| return mParser.getAttributeValue(namespace, name); |
| } |
| |
| @Override |
| public int next() throws XmlPullParserException, IOException { |
| if (!mStarted) { |
| mStarted = true; |
| |
| if (ParserFactory.LOG_PARSER) { |
| System.out.println("STRT " + mParser.toString()); |
| } |
| |
| return START_DOCUMENT; |
| } |
| |
| int ev = mParser.next(); |
| |
| if (ParserFactory.LOG_PARSER) { |
| System.out.println("NEXT " + mParser.toString() + " " + |
| eventTypeToString(mEventType) + " -> " + eventTypeToString(ev)); |
| } |
| |
| if (ev == END_TAG && mParser.getDepth() == 1) { |
| // done with parser remove it from the context stack. |
| ensurePopped(); |
| |
| if (ParserFactory.LOG_PARSER) { |
| System.out.println(""); |
| } |
| } |
| |
| mEventType = ev; |
| return ev; |
| } |
| |
| private static String eventTypeToString(int eventType) { |
| switch (eventType) { |
| case START_DOCUMENT: |
| return "START_DOC"; |
| case END_DOCUMENT: |
| return "END_DOC"; |
| case START_TAG: |
| return "START_TAG"; |
| case END_TAG: |
| return "END_TAG"; |
| case TEXT: |
| return "TEXT"; |
| case CDSECT: |
| return "CDSECT"; |
| case ENTITY_REF: |
| return "ENTITY_REF"; |
| case IGNORABLE_WHITESPACE: |
| return "IGNORABLE_WHITESPACE"; |
| case PROCESSING_INSTRUCTION: |
| return "PROCESSING_INSTRUCTION"; |
| case COMMENT: |
| return "COMMENT"; |
| case DOCDECL: |
| return "DOCDECL"; |
| } |
| |
| return "????"; |
| } |
| |
| @Override |
| public void require(int type, String namespace, String name) |
| throws XmlPullParserException { |
| if (type != getEventType() |
| || (namespace != null && !namespace.equals(getNamespace())) |
| || (name != null && !name.equals(getName()))) |
| throw new XmlPullParserException("expected " + TYPES[type] |
| + getPositionDescription()); |
| } |
| |
| @Override |
| public String nextText() throws XmlPullParserException, IOException { |
| if (getEventType() != START_TAG) { |
| throw new XmlPullParserException(getPositionDescription() |
| + ": parser must be on START_TAG to read next text", this, |
| null); |
| } |
| int eventType = next(); |
| if (eventType == TEXT) { |
| String result = getText(); |
| eventType = next(); |
| if (eventType != END_TAG) { |
| throw new XmlPullParserException( |
| getPositionDescription() |
| + ": event TEXT it must be immediately followed by END_TAG", |
| this, null); |
| } |
| return result; |
| } else if (eventType == END_TAG) { |
| return ""; |
| } else { |
| throw new XmlPullParserException(getPositionDescription() |
| + ": parser must be on START_TAG or TEXT to read text", |
| this, null); |
| } |
| } |
| |
| @Override |
| public int nextTag() throws XmlPullParserException, IOException { |
| int eventType = next(); |
| if (eventType == TEXT && isWhitespace()) { // skip whitespace |
| eventType = next(); |
| } |
| if (eventType != START_TAG && eventType != END_TAG) { |
| throw new XmlPullParserException(getPositionDescription() |
| + ": expected start or end tag", this, null); |
| } |
| return eventType; |
| } |
| |
| // AttributeSet implementation |
| |
| |
| @Override |
| public void close() { |
| // pass |
| } |
| |
| @Override |
| public boolean getAttributeBooleanValue(int index, boolean defaultValue) { |
| return mAttrib.getAttributeBooleanValue(index, defaultValue); |
| } |
| |
| @Override |
| public boolean getAttributeBooleanValue(String namespace, String attribute, |
| boolean defaultValue) { |
| return mAttrib.getAttributeBooleanValue(namespace, attribute, defaultValue); |
| } |
| |
| @Override |
| public float getAttributeFloatValue(int index, float defaultValue) { |
| return mAttrib.getAttributeFloatValue(index, defaultValue); |
| } |
| |
| @Override |
| public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) { |
| return mAttrib.getAttributeFloatValue(namespace, attribute, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeIntValue(int index, int defaultValue) { |
| return mAttrib.getAttributeIntValue(index, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeIntValue(String namespace, String attribute, int defaultValue) { |
| return mAttrib.getAttributeIntValue(namespace, attribute, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeListValue(int index, String[] options, int defaultValue) { |
| return mAttrib.getAttributeListValue(index, options, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeListValue(String namespace, String attribute, |
| String[] options, int defaultValue) { |
| return mAttrib.getAttributeListValue(namespace, attribute, options, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeNameResource(int index) { |
| return mAttrib.getAttributeNameResource(index); |
| } |
| |
| @Override |
| public int getAttributeResourceValue(int index, int defaultValue) { |
| return mAttrib.getAttributeResourceValue(index, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) { |
| return mAttrib.getAttributeResourceValue(namespace, attribute, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeUnsignedIntValue(int index, int defaultValue) { |
| return mAttrib.getAttributeUnsignedIntValue(index, defaultValue); |
| } |
| |
| @Override |
| public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) { |
| return mAttrib.getAttributeUnsignedIntValue(namespace, attribute, defaultValue); |
| } |
| |
| @Override |
| public String getClassAttribute() { |
| return mAttrib.getClassAttribute(); |
| } |
| |
| @Override |
| public String getIdAttribute() { |
| return mAttrib.getIdAttribute(); |
| } |
| |
| @Override |
| public int getIdAttributeResourceValue(int defaultValue) { |
| return mAttrib.getIdAttributeResourceValue(defaultValue); |
| } |
| |
| @Override |
| public int getStyleAttribute() { |
| return mAttrib.getStyleAttribute(); |
| } |
| |
| } |