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