• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.layoutlib.bridge.android;
17 
18 import com.android.ide.common.rendering.api.ILayoutPullParser;
19 import com.android.ide.common.rendering.api.ResourceNamespace;
20 import com.android.ide.common.rendering.api.ResourceValue;
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 import android.util.ResolvingAttributeSet;
32 
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.Reader;
36 
37 /**
38  * {@link BridgeXmlBlockParser} reimplements most of android.xml.XmlBlock.Parser.
39  * It delegates to both an instance of {@link XmlPullParser} and an instance of
40  * XmlPullAttributes (for the {@link AttributeSet} part).
41  */
42 public class BridgeXmlBlockParser implements XmlResourceParser, ResolvingAttributeSet {
43     @NonNull private final XmlPullParser mParser;
44     @NonNull private final ResolvingAttributeSet mAttrib;
45     @Nullable private final BridgeContext mContext;
46     @NonNull private final ResourceNamespace mFileResourceNamespace;
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 XmlPullParser to get the content from.
56      * @param context the Context.
57      * @param fileNamespace namespace of the file being parsed.
58      */
BridgeXmlBlockParser( @onNull XmlPullParser parser, @Nullable BridgeContext context, @NonNull ResourceNamespace fileNamespace)59     public BridgeXmlBlockParser(
60             @NonNull XmlPullParser parser,
61             @Nullable BridgeContext context,
62             @NonNull ResourceNamespace fileNamespace) {
63         if (ParserFactory.LOG_PARSER) {
64             System.out.println("CRTE " + parser.toString());
65         }
66 
67         mParser = parser;
68         mContext = context;
69         mFileResourceNamespace = fileNamespace;
70 
71         if (mContext != null) {
72             mAttrib = new BridgeXmlPullAttributes(parser, context, mFileResourceNamespace);
73             mContext.pushParser(this);
74             mPopped = false;
75         }
76         else {
77             mAttrib = new NopAttributeSet();
78         }
79     }
80 
getParser()81     public XmlPullParser getParser() {
82         return mParser;
83     }
84 
85     @NonNull
getFileResourceNamespace()86     public ResourceNamespace getFileResourceNamespace() {
87         return mFileResourceNamespace;
88     }
89 
getViewCookie()90     public Object getViewCookie() {
91         if (mParser instanceof ILayoutPullParser) {
92             return ((ILayoutPullParser)mParser).getViewCookie();
93         }
94 
95         return null;
96     }
97 
ensurePopped()98     public void ensurePopped() {
99         if (mContext != null && !mPopped) {
100             mContext.popParser();
101             mPopped = true;
102         }
103     }
104 
105     // ------- XmlResourceParser implementation
106 
107     @Override
setFeature(String name, boolean state)108     public void setFeature(String name, boolean state)
109             throws XmlPullParserException {
110         if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
111             return;
112         }
113         if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) {
114             return;
115         }
116         throw new XmlPullParserException("Unsupported feature: " + name);
117     }
118 
119     @Override
getFeature(String name)120     public boolean getFeature(String name) {
121         return FEATURE_PROCESS_NAMESPACES.equals(name) ||
122                 FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name);
123     }
124 
125     @Override
setProperty(String name, Object value)126     public void setProperty(String name, Object value) throws XmlPullParserException {
127         throw new XmlPullParserException("setProperty() not supported");
128     }
129 
130     @Override
getProperty(String name)131     public Object getProperty(String name) {
132         return null;
133     }
134 
135     @Override
setInput(Reader in)136     public void setInput(Reader in) throws XmlPullParserException {
137         mParser.setInput(in);
138     }
139 
140     @Override
setInput(InputStream inputStream, String inputEncoding)141     public void setInput(InputStream inputStream, String inputEncoding)
142             throws XmlPullParserException {
143         mParser.setInput(inputStream, inputEncoding);
144     }
145 
146     @Override
defineEntityReplacementText(String entityName, String replacementText)147     public void defineEntityReplacementText(String entityName,
148             String replacementText) throws XmlPullParserException {
149         throw new XmlPullParserException(
150                 "defineEntityReplacementText() not supported");
151     }
152 
153     @Override
getNamespacePrefix(int pos)154     public String getNamespacePrefix(int pos) throws XmlPullParserException {
155         throw new XmlPullParserException("getNamespacePrefix() not supported");
156     }
157 
158     @Override
getInputEncoding()159     public String getInputEncoding() {
160         return null;
161     }
162 
163     @Override
getNamespace(String prefix)164     public String getNamespace(String prefix) {
165         return mParser.getNamespace(prefix);
166     }
167 
168     @Override
getNamespaceCount(int depth)169     public int getNamespaceCount(int depth) throws XmlPullParserException {
170         throw new XmlPullParserException("getNamespaceCount() not supported");
171     }
172 
173     @Override
getPositionDescription()174     public String getPositionDescription() {
175         return "Binary XML file line #" + getLineNumber();
176     }
177 
178     @Override
getNamespaceUri(int pos)179     public String getNamespaceUri(int pos) throws XmlPullParserException {
180         throw new XmlPullParserException("getNamespaceUri() not supported");
181     }
182 
183     @Override
getColumnNumber()184     public int getColumnNumber() {
185         return -1;
186     }
187 
188     @Override
getDepth()189     public int getDepth() {
190         return mParser.getDepth();
191     }
192 
193     @Override
getText()194     public String getText() {
195         return mParser.getText();
196     }
197 
198     @Override
getLineNumber()199     public int getLineNumber() {
200         return mParser.getLineNumber();
201     }
202 
203     @Override
getEventType()204     public int getEventType() {
205         return mEventType;
206     }
207 
208     @Override
isWhitespace()209     public boolean isWhitespace() throws XmlPullParserException {
210         // Original comment: whitespace was stripped by aapt.
211         return mParser.isWhitespace();
212     }
213 
214     @Override
getPrefix()215     public String getPrefix() {
216         throw new RuntimeException("getPrefix not supported");
217     }
218 
219     @Override
getTextCharacters(int[] holderForStartAndLength)220     public char[] getTextCharacters(int[] holderForStartAndLength) {
221         String txt = getText();
222         char[] chars = null;
223         if (txt != null) {
224             holderForStartAndLength[0] = 0;
225             holderForStartAndLength[1] = txt.length();
226             chars = new char[txt.length()];
227             txt.getChars(0, txt.length(), chars, 0);
228         }
229         return chars;
230     }
231 
232     @Override
getNamespace()233     public String getNamespace() {
234         return mParser.getNamespace();
235     }
236 
237     @Override
getName()238     public String getName() {
239         return mParser.getName();
240     }
241 
242     @Override
getAttributeNamespace(int index)243     public String getAttributeNamespace(int index) {
244         return mParser.getAttributeNamespace(index);
245     }
246 
247     @Override
getAttributeName(int index)248     public String getAttributeName(int index) {
249         return mParser.getAttributeName(index);
250     }
251 
252     @Override
getAttributePrefix(int index)253     public String getAttributePrefix(int index) {
254         throw new RuntimeException("getAttributePrefix not supported");
255     }
256 
257     @Override
isEmptyElementTag()258     public boolean isEmptyElementTag() {
259         // XXX Need to detect this.
260         return false;
261     }
262 
263     @Override
getAttributeCount()264     public int getAttributeCount() {
265         return mParser.getAttributeCount();
266     }
267 
268     @Override
getAttributeValue(int index)269     public String getAttributeValue(int index) {
270         return mParser.getAttributeValue(index);
271     }
272 
273     @Override
getAttributeType(int index)274     public String getAttributeType(int index) {
275         return "CDATA";
276     }
277 
278     @Override
isAttributeDefault(int index)279     public boolean isAttributeDefault(int index) {
280         return false;
281     }
282 
283     @Override
nextToken()284     public int nextToken() throws XmlPullParserException, IOException {
285         return next();
286     }
287 
288     @Override
getAttributeValue(String namespace, String name)289     public String getAttributeValue(String namespace, String name) {
290         return mParser.getAttributeValue(namespace, name);
291     }
292 
293     @Override
next()294     public int next() throws XmlPullParserException, IOException {
295         if (!mStarted) {
296             mStarted = true;
297 
298             if (ParserFactory.LOG_PARSER) {
299                 System.out.println("STRT " + mParser.toString());
300             }
301 
302             return START_DOCUMENT;
303         }
304 
305         int ev = mParser.next();
306 
307         if (ParserFactory.LOG_PARSER) {
308             System.out.println("NEXT " + mParser.toString() + " " +
309                     eventTypeToString(mEventType) + " -> " + eventTypeToString(ev));
310         }
311 
312         if (ev == END_TAG && mParser.getDepth() == 1) {
313             // done with parser remove it from the context stack.
314             ensurePopped();
315         }
316 
317         mEventType = ev;
318         return ev;
319     }
320 
eventTypeToString(int eventType)321     private 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
require(int type, String namespace, String name)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
nextText()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
nextTag()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
close()404     public void close() {
405         // pass
406     }
407 
408     @Override
getAttributeBooleanValue(int index, boolean defaultValue)409     public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
410         return mAttrib.getAttributeBooleanValue(index, defaultValue);
411     }
412 
413     @Override
getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue)414     public boolean getAttributeBooleanValue(String namespace, String attribute,
415             boolean defaultValue) {
416         return mAttrib.getAttributeBooleanValue(namespace, attribute, defaultValue);
417     }
418 
419     @Override
getAttributeFloatValue(int index, float defaultValue)420     public float getAttributeFloatValue(int index, float defaultValue) {
421         return mAttrib.getAttributeFloatValue(index, defaultValue);
422     }
423 
424     @Override
getAttributeFloatValue(String namespace, String attribute, float defaultValue)425     public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
426         return mAttrib.getAttributeFloatValue(namespace, attribute, defaultValue);
427     }
428 
429     @Override
getAttributeIntValue(int index, int defaultValue)430     public int getAttributeIntValue(int index, int defaultValue) {
431         return mAttrib.getAttributeIntValue(index, defaultValue);
432     }
433 
434     @Override
getAttributeIntValue(String namespace, String attribute, int defaultValue)435     public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
436         return mAttrib.getAttributeIntValue(namespace, attribute, defaultValue);
437     }
438 
439     @Override
getAttributeListValue(int index, String[] options, int defaultValue)440     public int getAttributeListValue(int index, String[] options, int defaultValue) {
441         return mAttrib.getAttributeListValue(index, options, defaultValue);
442     }
443 
444     @Override
getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue)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
getAttributeNameResource(int index)451     public int getAttributeNameResource(int index) {
452         return mAttrib.getAttributeNameResource(index);
453     }
454 
455     @Override
getAttributeResourceValue(int index, int defaultValue)456     public int getAttributeResourceValue(int index, int defaultValue) {
457         return mAttrib.getAttributeResourceValue(index, defaultValue);
458     }
459 
460     @Override
getAttributeResourceValue(String namespace, String attribute, int defaultValue)461     public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
462         return mAttrib.getAttributeResourceValue(namespace, attribute, defaultValue);
463     }
464 
465     @Override
getAttributeUnsignedIntValue(int index, int defaultValue)466     public int getAttributeUnsignedIntValue(int index, int defaultValue) {
467         return mAttrib.getAttributeUnsignedIntValue(index, defaultValue);
468     }
469 
470     @Override
getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue)471     public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
472         return mAttrib.getAttributeUnsignedIntValue(namespace, attribute, defaultValue);
473     }
474 
475     @Override
getClassAttribute()476     public String getClassAttribute() {
477         return mAttrib.getClassAttribute();
478     }
479 
480     @Override
getIdAttribute()481     public String getIdAttribute() {
482         return mAttrib.getIdAttribute();
483     }
484 
485     @Override
getIdAttributeResourceValue(int defaultValue)486     public int getIdAttributeResourceValue(int defaultValue) {
487         return mAttrib.getIdAttributeResourceValue(defaultValue);
488     }
489 
490     @Override
getStyleAttribute()491     public int getStyleAttribute() {
492         return mAttrib.getStyleAttribute();
493     }
494 
495     @Override
496     @Nullable
getResolvedAttributeValue(@ullable String namespace, @NonNull String name)497     public ResourceValue getResolvedAttributeValue(@Nullable String namespace,
498             @NonNull String name) {
499         return mAttrib.getResolvedAttributeValue(namespace, name);
500     }
501 }
502