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