aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Prigogin <sprigogin@google.com>2018-05-02 16:46:32 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2018-05-02 16:46:32 +0000
commit9cbea8e8d1028641fe78e26f65b178954909bd71 (patch)
tree1cecc3c76df66b821caab5862f9284692bb0fc44
parent54cff2c1941cf39d037c1d2f5e2a00503a95d5ca (diff)
parent0cf4b48ebe0b89025e49cccffcb8cc4c20efefc2 (diff)
downloadlayoutlib-9cbea8e8d1028641fe78e26f65b178954909bd71.tar.gz
Merge "Delegate resource file operations to AssetRepository" into pi-layoutlib-dev
-rw-r--r--bridge/src/android/content/res/Resources_Delegate.java100
-rw-r--r--bridge/src/android/graphics/Bitmap_Delegate.java48
-rw-r--r--bridge/src/android/graphics/Typeface_Delegate.java18
-rw-r--r--bridge/src/android/util/Xml_Delegate.java3
-rw-r--r--bridge/src/android/view/BridgeInflater.java25
-rw-r--r--bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java37
-rw-r--r--bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java2
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java98
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java2
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java73
-rw-r--r--bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java57
-rw-r--r--bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java35
-rw-r--r--bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java20
-rw-r--r--bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java47
-rw-r--r--remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java13
-rw-r--r--remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java12
16 files changed, 308 insertions, 282 deletions
diff --git a/bridge/src/android/content/res/Resources_Delegate.java b/bridge/src/android/content/res/Resources_Delegate.java
index 2cbf86c7c4..84749c4cf3 100644
--- a/bridge/src/android/content/res/Resources_Delegate.java
+++ b/bridge/src/android/content/res/Resources_Delegate.java
@@ -18,6 +18,7 @@ package android.content.res;
import com.android.SdkConstants;
import com.android.ide.common.rendering.api.ArrayResourceValue;
+import com.android.ide.common.rendering.api.AssetRepository;
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.LayoutlibCallback;
@@ -59,14 +60,13 @@ import android.util.TypedValue;
import android.view.DisplayAdjustments;
import android.view.ViewGroup.LayoutParams;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Objects;
import java.util.WeakHashMap;
+import static android.content.res.AssetManager.ACCESS_STREAMING;
import static com.android.SdkConstants.ANDROID_PKG;
import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
@@ -230,8 +230,9 @@ public class Resources_Delegate {
} catch (NumberFormatException e) {
// Check if the value passed is a file. If it is, mostly likely, user is referencing
// a color state list from a place where they should reference only a pure color.
+ AssetRepository repository = getAssetRepository(resources);
String message;
- if (new File(resourceValue.getValue()).isFile()) {
+ if (repository.isFileResource(resourceValue.getValue())) {
String resource = (resourceValue.isFramework() ? "@android:" : "@") + "color/"
+ resourceValue.getName();
message = "Hexadecimal color expected, found Color State List for " + resource;
@@ -476,12 +477,9 @@ public class Resources_Delegate {
return ResourceHelper.getXmlBlockParser(getContext(resources), value);
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Failed to configure parser for " + value.getValue(), e, null /*data*/);
+ "Failed to parse " + value.getValue(), e, null /*data*/);
// we'll return null below.
- } catch (FileNotFoundException e) {
- // this shouldn't happen since we check above.
}
-
}
// id was not found or not resolved. Throw a NotFoundException.
@@ -502,12 +500,9 @@ public class Resources_Delegate {
return ResourceHelper.getXmlBlockParser(getContext(resources), value);
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Failed to configure parser for " + value.getValue(), e, null /*data*/);
+ "Failed to parse " + value.getValue(), e, null /*data*/);
// we'll return null below.
- } catch (FileNotFoundException e) {
- // this shouldn't happen since we check above.
}
-
}
// id was not found or not resolved. Throw a NotFoundException.
@@ -904,10 +899,8 @@ public class Resources_Delegate {
return ResourceHelper.getXmlBlockParser(getContext(resources), value);
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Failed to configure parser for " + value.getValue(), e, null /*data*/);
+ "Failed to parse " + value.getValue(), e, null /*data*/);
// we'll return null below.
- } catch (FileNotFoundException e) {
- // this shouldn't happen since we check above.
}
}
@@ -930,8 +923,7 @@ public class Resources_Delegate {
// even though we know the XML file to load directly, we still need to resolve the
// id so that we can know if it's a platform or project resource.
// (mPlatformResouceFlag will get the result and will be used later).
- Pair<String, ResourceValue> result =
- getResourceValue(resources, id, mPlatformResourceFlag);
+ Pair<String, ResourceValue> result = getResourceValue(resources, id, mPlatformResourceFlag);
ResourceNamespace layoutNamespace;
if (result != null && result.getSecond() != null) {
@@ -942,19 +934,13 @@ public class Resources_Delegate {
layoutNamespace = ResourceNamespace.RES_AUTO;
}
- File f = new File(file);
try {
- XmlPullParser parser = ParserFactory.create(f);
-
+ XmlPullParser parser = ParserFactory.create(file);
return new BridgeXmlBlockParser(parser, getContext(resources), layoutNamespace);
} catch (XmlPullParserException e) {
NotFoundException newE = new NotFoundException();
newE.initCause(e);
throw newE;
- } catch (FileNotFoundException e) {
- NotFoundException newE = new NotFoundException();
- newE.initCause(e);
- throw newE;
}
}
@@ -964,25 +950,8 @@ public class Resources_Delegate {
if (value != null) {
String path = value.getSecond().getValue();
-
if (path != null) {
- // check this is a file
- File f = new File(path);
- if (f.isFile()) {
- try {
- // if it's a nine-patch return a custom input stream so that
- // other methods (mainly bitmap factory) can detect it's a 9-patch
- // and actually load it as a 9-patch instead of a normal bitmap
- if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
- return new NinePatchInputStream(f);
- }
- return new FileInputStream(f);
- } catch (FileNotFoundException e) {
- NotFoundException newE = new NotFoundException();
- newE.initCause(e);
- throw newE;
- }
- }
+ return openRawResource(resources, path);
}
}
@@ -994,35 +963,36 @@ public class Resources_Delegate {
}
@LayoutlibDelegate
- static InputStream openRawResource(Resources resources, int id, TypedValue value) throws
- NotFoundException {
+ static InputStream openRawResource(Resources resources, int id, TypedValue value)
+ throws NotFoundException {
getValue(resources, id, value, true);
String path = value.string.toString();
+ return openRawResource(resources, path);
+ }
- File f = new File(path);
- if (f.isFile()) {
- try {
- // if it's a nine-patch return a custom input stream so that
- // other methods (mainly bitmap factory) can detect it's a 9-patch
- // and actually load it as a 9-patch instead of a normal bitmap
- if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
- return new NinePatchInputStream(f);
- }
- return new FileInputStream(f);
- } catch (FileNotFoundException e) {
- NotFoundException exception = new NotFoundException();
- exception.initCause(e);
- throw exception;
+ private static InputStream openRawResource(Resources resources, String path)
+ throws NotFoundException {
+ AssetRepository repository = getAssetRepository(resources);
+ try {
+ InputStream stream = repository.openNonAsset(0, path, ACCESS_STREAMING);
+ // If it's a nine-patch return a custom input stream so that
+ // other methods (mainly bitmap factory) can detect it's a 9-patch
+ // and actually load it as a 9-patch instead of a normal bitmap.
+ if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
+ return new NinePatchInputStream(stream);
}
+ return stream;
+ } catch (IOException e) {
+ NotFoundException exception = new NotFoundException();
+ exception.initCause(e);
+ throw exception;
}
-
- throw new NotFoundException();
}
@LayoutlibDelegate
- static AssetFileDescriptor openRawResourceFd(Resources resources, int id) throws
- NotFoundException {
+ static AssetFileDescriptor openRawResourceFd(Resources resources, int id)
+ throws NotFoundException {
throw new UnsupportedOperationException();
}
@@ -1129,4 +1099,10 @@ public class Resources_Delegate {
}
return Integer.parseInt(v, radix);
}
+
+ private static AssetRepository getAssetRepository(Resources resources) {
+ BridgeContext context = getContext(resources);
+ BridgeAssetManager assetManager = context.getAssets();
+ return assetManager.getAssetRepository();
+ }
}
diff --git a/bridge/src/android/graphics/Bitmap_Delegate.java b/bridge/src/android/graphics/Bitmap_Delegate.java
index 72344b3b0d..49cad43f30 100644
--- a/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -60,7 +60,6 @@ import libcore.util.NativeAllocationRegistry_Delegate;
*/
public final class Bitmap_Delegate {
-
public enum BitmapCreateFlags {
NONE, PREMULTIPLIED, MUTABLE
}
@@ -96,17 +95,17 @@ public final class Bitmap_Delegate {
}
/**
- * Creates and returns a {@link Bitmap} initialized with the given file content.
+ * Creates and returns a {@link Bitmap} initialized with the given stream content.
*
- * @param input the file from which to read the bitmap content
+ * @param input the stream from which to read the bitmap content
* @param isMutable whether the bitmap is mutable
* @param density the density associated with the bitmap
*
* @see Bitmap#isMutable()
* @see Bitmap#getDensity()
*/
- public static Bitmap createBitmap(File input, boolean isMutable, Density density)
- throws IOException {
+ public static Bitmap createBitmap(@Nullable InputStream input, boolean isMutable,
+ Density density) throws IOException {
return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
}
@@ -120,11 +119,11 @@ public final class Bitmap_Delegate {
* @see Bitmap#isMutable()
* @see Bitmap#getDensity()
*/
- private static Bitmap createBitmap(File input, Set<BitmapCreateFlags> createFlags,
+ static Bitmap createBitmap(@Nullable InputStream input, Set<BitmapCreateFlags> createFlags,
Density density) throws IOException {
// create a delegate with the content of the file.
- BufferedImage image = ImageIO.read(input);
- if (image == null && input.exists()) {
+ BufferedImage image = input == null ? null : ImageIO.read(input);
+ if (image == null) {
// There was a problem decoding the image, or the decoder isn't registered. Webp maybe.
// Replace with a broken image icon.
BridgeContext currentContext = RenderAction.getCurrentContext();
@@ -144,39 +143,6 @@ public final class Bitmap_Delegate {
}
/**
- * Creates and returns a {@link Bitmap} initialized with the given stream content.
- *
- * @param input the stream from which to read the bitmap content
- * @param isMutable whether the bitmap is mutable
- * @param density the density associated with the bitmap
- *
- * @see Bitmap#isMutable()
- * @see Bitmap#getDensity()
- */
- public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density)
- throws IOException {
- return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
- }
-
- /**
- * Creates and returns a {@link Bitmap} initialized with the given stream content.
- *
- * @param input the stream from which to read the bitmap content
- * @param density the density associated with the bitmap
- *
- * @see Bitmap#isPremultiplied()
- * @see Bitmap#isMutable()
- * @see Bitmap#getDensity()
- */
- public static Bitmap createBitmap(InputStream input, Set<BitmapCreateFlags> createFlags,
- Density density) throws IOException {
- // create a delegate with the content of the stream.
- Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
-
- return createBitmap(delegate, createFlags, density.getDpiValue());
- }
-
- /**
* Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
*
* @param image the bitmap content
diff --git a/bridge/src/android/graphics/Typeface_Delegate.java b/bridge/src/android/graphics/Typeface_Delegate.java
index c492cb9700..bde71415f8 100644
--- a/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/bridge/src/android/graphics/Typeface_Delegate.java
@@ -24,7 +24,6 @@ import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.android.RenderParamsFlags;
import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.RenderAction;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
@@ -40,8 +39,6 @@ import android.text.FontConfig;
import android.util.ArrayMap;
import java.awt.Font;
-import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
@@ -272,20 +269,9 @@ public final class Typeface_Delegate {
RenderParamsFlags.FLAG_KEY_XML_FILE_PARSER_SUPPORT);
XmlPullParser parser = null;
if (psiParserSupport != null && psiParserSupport) {
- parser = context.getLayoutlibCallback().getXmlFileParser(path);
+ parser = context.getLayoutlibCallback().createXmlParserForPsiFile(path);
} else {
- File f = new File(path);
- if (f.isFile()) {
- try {
- parser = ParserFactory.create(f);
- } catch (XmlPullParserException | FileNotFoundException e) {
- // this is an error and not warning since the file existence is checked
- // before
- // attempting to parse it.
- Bridge.getLog().error(null, "Failed to parse file " + path, e,
- null /*data*/);
- }
- }
+ parser = context.getLayoutlibCallback().createXmlParserForFile(path);
}
if (parser != null) {
diff --git a/bridge/src/android/util/Xml_Delegate.java b/bridge/src/android/util/Xml_Delegate.java
index 213e848659..e309dc6cfd 100644
--- a/bridge/src/android/util/Xml_Delegate.java
+++ b/bridge/src/android/util/Xml_Delegate.java
@@ -33,11 +33,10 @@ import org.xmlpull.v1.XmlPullParserException;
* around to map int to instance of the delegate.
*/
public class Xml_Delegate {
-
@LayoutlibDelegate
/*package*/ static XmlPullParser newPullParser() {
try {
- return ParserFactory.instantiateParser(null);
+ return ParserFactory.create();
} catch (XmlPullParserException e) {
throw new AssertionError();
}
diff --git a/bridge/src/android/view/BridgeInflater.java b/bridge/src/android/view/BridgeInflater.java
index 603738f8ec..a13ee6cda5 100644
--- a/bridge/src/android/view/BridgeInflater.java
+++ b/bridge/src/android/view/BridgeInflater.java
@@ -347,21 +347,22 @@ public final class BridgeInflater extends LayoutInflater {
}
if (value != null) {
- File f = new File(value.getValue());
- if (f.isFile()) {
- try {
- XmlPullParser parser = ParserFactory.create(f, true);
+ String path = value.getValue();
+ try {
+ XmlPullParser parser = ParserFactory.create(path, true);
+ if (parser == null) {
+ return null;
+ }
- BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
- parser, bridgeContext, value.getNamespace());
+ BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
+ parser, bridgeContext, value.getNamespace());
- return inflate(bridgeParser, root);
- } catch (Exception e) {
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- "Failed to parse file " + f.getAbsolutePath(), e, null);
+ return inflate(bridgeParser, root);
+ } catch (Exception e) {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed to parse file " + path, e, null);
- return null;
- }
+ return null;
}
}
}
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 086c33fbe4..1ed13dfb97 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -465,39 +465,34 @@ public class BridgeContext extends Context {
}
if (resValue != null) {
-
- File xml = new File(resValue.getValue());
- if (xml.isFile()) {
- // we need to create a pull parser around the layout XML file, and then
- // give that to our XmlBlockParser
- try {
- XmlPullParser parser = ParserFactory.create(xml, true);
-
- // set the layout ref to have correct view cookies
+ String path = resValue.getValue();
+ // We need to create a pull parser around the layout XML file, and then
+ // give that to our XmlBlockParser.
+ try {
+ XmlPullParser parser = ParserFactory.create(path, true);
+ if (parser != null) {
+ // Set the layout ref to have correct view cookies.
mBridgeInflater.setResourceReference(layout);
BridgeXmlBlockParser blockParser =
- new BridgeXmlBlockParser(parser,this, layout.getNamespace());
+ new BridgeXmlBlockParser(parser, this, layout.getNamespace());
try {
pushParser(blockParser);
- return Pair.of(
- mBridgeInflater.inflate(blockParser, parent, attachToRoot),
+ return Pair.of(mBridgeInflater.inflate(blockParser, parent, attachToRoot),
Boolean.FALSE);
} finally {
popParser();
}
- } catch (XmlPullParserException e) {
+ } else {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- "Failed to configure parser for " + xml, e, null /*data*/);
- // we'll return null below.
- } catch (FileNotFoundException e) {
- // this shouldn't happen since we check above.
- } finally {
- mBridgeInflater.setResourceReference(null);
+ String.format("File %s is missing!", path), null);
}
- } else {
+ } catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- String.format("File %s is missing!", xml), null);
+ "Failed to parse file " + path, e, null /*data*/);
+ // We'll return null below.
+ } finally {
+ mBridgeInflater.setResourceReference(null);
}
} else {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index c023e365e5..aa52ff538c 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -104,7 +104,7 @@ public class StatusBar extends CustomBar {
try {
BridgeXmlBlockParser parser =
new BridgeXmlBlockParser(
- ParserFactory.create(stream, null),
+ ParserFactory.create(stream, iconName),
(BridgeContext) mContext,
ResourceNamespace.ANDROID);
imageView.setImageDrawable(
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
index 1ae9cb646c..38b7aa5008 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.impl;
+import com.android.ide.common.rendering.api.XmlParserFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -25,55 +26,34 @@ import android.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* A factory for {@link XmlPullParser}.
- *
*/
public class ParserFactory {
-
public final static boolean LOG_PARSER = false;
// Used to get a new XmlPullParser from the client.
@Nullable
- private static com.android.ide.common.rendering.api.ParserFactory sParserFactory;
+ private static XmlParserFactory sParserFactory;
- public static void setParserFactory(
- @Nullable com.android.ide.common.rendering.api.ParserFactory parserFactory) {
+ public static void setParserFactory(@Nullable XmlParserFactory parserFactory) {
sParserFactory = parserFactory;
}
- @NonNull
- public static XmlPullParser create(@NonNull File f)
- throws XmlPullParserException, FileNotFoundException {
- return create(f, false);
- }
-
- public static XmlPullParser create(@NonNull File f, boolean isLayout)
- throws XmlPullParserException, FileNotFoundException {
- InputStream stream = new FileInputStream(f);
- return create(stream, f.getName(), f.length(), isLayout);
- }
- @NonNull
- public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
- throws XmlPullParserException {
- return create(stream, name, -1, false);
+ @Nullable
+ public static XmlPullParser create(@NonNull String filePath)
+ throws XmlPullParserException {
+ return create(filePath, false);
}
- @NonNull
- private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name,
- long size, boolean isLayout) throws XmlPullParserException {
- XmlPullParser parser = instantiateParser(name);
-
- stream = readAndClose(stream, name, size);
-
- parser.setInput(stream, null);
- if (isLayout) {
+ @Nullable
+ public static XmlPullParser create(@NonNull String filePath, boolean isLayout)
+ throws XmlPullParserException {
+ XmlPullParser parser = sParserFactory.createXmlParserForFile(filePath);
+ if (parser != null && isLayout) {
try {
return new LayoutParserWrapper(parser).peekTillLayoutStart();
} catch (IOException e) {
@@ -84,46 +64,38 @@ public class ParserFactory {
}
@NonNull
- public static XmlPullParser instantiateParser(@Nullable String name)
+ public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
throws XmlPullParserException {
+ XmlPullParser parser = create();
+
+ stream = readAndClose(stream, name);
+
+ parser.setInput(stream, null);
+ return parser;
+ }
+
+ @NonNull
+ public static XmlPullParser create() throws XmlPullParserException {
if (sParserFactory == null) {
throw new XmlPullParserException("ParserFactory not initialized.");
}
- XmlPullParser parser = sParserFactory.createParser(name);
+ XmlPullParser parser = sParserFactory.createXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
return parser;
}
@NonNull
- private static InputStream readAndClose(@NonNull InputStream stream, @Nullable String name,
- long size) throws XmlPullParserException {
- // just a sanity check. It's doubtful we'll have such big files!
- if (size > Integer.MAX_VALUE) {
- throw new XmlPullParserException("File " + name + " is too big to be parsed");
- }
- int intSize = (int) size;
-
- // create a buffered reader to facilitate reading.
- BufferedInputStream bufferedStream = new BufferedInputStream(stream);
- try {
- int avail;
- if (intSize != -1) {
- avail = intSize;
- } else {
- // get the size to read.
- avail = bufferedStream.available();
- }
+ private static InputStream readAndClose(@NonNull InputStream stream, @Nullable String name)
+ throws XmlPullParserException {
+ // Create a buffered stream to facilitate reading.
+ try (BufferedInputStream bufferedStream = new BufferedInputStream(stream)) {
+ int avail = bufferedStream.available();
- // create the initial buffer and read it.
+ // Create the initial buffer and read it.
byte[] buffer = new byte[avail];
int read = stream.read(buffer);
- // this is the easy case.
- if (read == intSize) {
- return new ByteArrayInputStream(buffer);
- }
-
- // check if there is more to read (read() does not necessarily read all that
+ // Check if there is more to read (read() does not necessarily read all that
// available() returned!)
while ((avail = bufferedStream.available()) > 0) {
if (read + avail > buffer.length) {
@@ -137,16 +109,10 @@ public class ParserFactory {
read += stream.read(buffer, read, avail);
}
- // return a new stream encapsulating this buffer.
+ // Return a new stream encapsulating this buffer.
return new ByteArrayInputStream(buffer);
-
} catch (IOException e) {
throw new XmlPullParserException("Failed to read " + name, null, e);
- } finally {
- try {
- bufferedStream.close();
- } catch (IOException ignored) {
- }
}
}
}
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index ae343ec892..91ed163673 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -233,7 +233,7 @@ public abstract class RenderAction<T extends RenderParams> {
*/
private void setUp() {
// setup the ParserFactory
- ParserFactory.setParserFactory(mParams.getLayoutlibCallback().getParserFactory());
+ ParserFactory.setParserFactory(mParams.getLayoutlibCallback());
// make sure the Resources object references the context (and other objects) for this
// scene
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index dd461dc4d3..04dc989af7 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -17,8 +17,10 @@
package com.android.layoutlib.bridge.impl;
import com.android.SdkConstants;
+import com.android.ide.common.rendering.api.AssetRepository;
import com.android.ide.common.rendering.api.DensityBasedResourceValue;
import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.LayoutlibCallback;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.internal.util.XmlUtils;
@@ -34,6 +36,7 @@ import org.xmlpull.v1.XmlPullParserException;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.res.BridgeAssetManager;
import android.content.res.ColorStateList;
import android.content.res.ComplexColor;
import android.content.res.ComplexColor_Accessor;
@@ -53,8 +56,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.util.TypedValue;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -62,6 +63,8 @@ import java.net.MalformedURLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static android.content.res.AssetManager.ACCESS_STREAMING;
+
/**
* Helper class to provide various conversion method used in handling android resources.
*/
@@ -252,8 +255,7 @@ public final class ResourceHelper {
*/
@Nullable
public static BridgeXmlBlockParser getXmlBlockParser(@NonNull BridgeContext context,
- @NonNull ResourceValue value)
- throws FileNotFoundException, XmlPullParserException {
+ @NonNull ResourceValue value) throws XmlPullParserException {
String stringValue = value.getValue();
if (RenderResources.REFERENCE_NULL.equals(stringValue)) {
return null;
@@ -261,17 +263,15 @@ public final class ResourceHelper {
XmlPullParser parser = null;
+ LayoutlibCallback layoutlibCallback = context.getLayoutlibCallback();
// Framework values never need a PSI parser. They do not change and the do not contain
// aapt:attr attributes.
if (!value.isFramework()) {
- parser = context.getLayoutlibCallback().getParser(value);
+ parser = layoutlibCallback.getParser(value);
}
if (parser == null) {
- File xmlFile = new File(stringValue);
- if (xmlFile.isFile()) {
- parser = ParserFactory.create(xmlFile);
- }
+ parser = ParserFactory.create(stringValue);
}
return parser == null
@@ -312,16 +312,12 @@ public final class ResourceHelper {
}
if (lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) {
- File file = new File(stringValue);
- if (file.isFile()) {
- try {
- return getNinePatchDrawable(new FileInputStream(file), density,
- value.isFramework(), stringValue, context);
- } catch (IOException e) {
- // failed to read the file, we'll return null below.
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- "Failed lot load " + file.getAbsolutePath(), e, null /*data*/);
- }
+ try {
+ return getNinePatchDrawable(density, value.isFramework(), stringValue, context);
+ } catch (IOException e) {
+ // failed to read the file, we'll return null below.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed to load " + stringValue, e, null /*data*/);
}
return null;
@@ -345,15 +341,22 @@ public final class ResourceHelper {
return null;
} else {
- File bmpFile = new File(stringValue);
- if (bmpFile.isFile()) {
+ AssetRepository repository = getAssetRepository(context);
+ if (repository.isFileResource(stringValue)) {
try {
Bitmap bitmap = Bridge.getCachedBitmap(stringValue,
value.isFramework() ? null : context.getProjectKey());
if (bitmap == null) {
+ InputStream stream;
+ try {
+ stream = repository.openNonAsset(0, stringValue, ACCESS_STREAMING);
+
+ } catch (FileNotFoundException e) {
+ stream = null;
+ }
bitmap =
- Bitmap_Delegate.createBitmap(bmpFile, false /*isMutable*/, density);
+ Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
Bridge.setCachedBitmap(stringValue, bitmap,
value.isFramework() ? null : context.getProjectKey());
}
@@ -362,7 +365,7 @@ public final class ResourceHelper {
} catch (IOException e) {
// we'll return null below
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
- "Failed lot load " + bmpFile.getAbsolutePath(), e, null /*data*/);
+ "Failed to load " + stringValue, e, null /*data*/);
}
}
}
@@ -370,6 +373,11 @@ public final class ResourceHelper {
return null;
}
+ private static AssetRepository getAssetRepository(@NonNull BridgeContext context) {
+ BridgeAssetManager assetManager = context.getAssets();
+ return assetManager.getAssetRepository();
+ }
+
/**
* Returns a {@link Typeface} given a font name. The font name, can be a system font family
* (like sans-serif) or a full path if the font is to be loaded from resources.
@@ -402,24 +410,29 @@ public final class ResourceHelper {
return getFont(value.getValue(), context, theme, value.isFramework());
}
- private static Drawable getNinePatchDrawable(InputStream inputStream, Density density,
- boolean isFramework, String cacheKey, BridgeContext context) throws IOException {
+ private static Drawable getNinePatchDrawable(Density density, boolean isFramework,
+ String path, BridgeContext context) throws IOException {
// see if we still have both the chunk and the bitmap in the caches
- NinePatchChunk chunk = Bridge.getCached9Patch(cacheKey,
+ NinePatchChunk chunk = Bridge.getCached9Patch(path,
isFramework ? null : context.getProjectKey());
- Bitmap bitmap = Bridge.getCachedBitmap(cacheKey,
+ Bitmap bitmap = Bridge.getCachedBitmap(path,
isFramework ? null : context.getProjectKey());
// if either chunk or bitmap is null, then we reload the 9-patch file.
if (chunk == null || bitmap == null) {
try {
- NinePatch ninePatch = NinePatch.load(inputStream, true /*is9Patch*/,
+ AssetRepository repository = getAssetRepository(context);
+ if (!repository.isFileResource(path)) {
+ return null;
+ }
+ InputStream stream = repository.openNonAsset(0, path, ACCESS_STREAMING);
+ NinePatch ninePatch = NinePatch.load(stream, true /*is9Patch*/,
false /* convert */);
if (ninePatch != null) {
if (chunk == null) {
chunk = ninePatch.getChunk();
- Bridge.setCached9Patch(cacheKey, chunk,
+ Bridge.setCached9Patch(path, chunk,
isFramework ? null : context.getProjectKey());
}
@@ -428,7 +441,7 @@ public final class ResourceHelper {
false /*isMutable*/,
density);
- Bridge.setCachedBitmap(cacheKey, bitmap,
+ Bridge.setCachedBitmap(path, bitmap,
isFramework ? null : context.getProjectKey());
}
}
diff --git a/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java b/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
index f149b6cd8e..75e4a2b2bf 100644
--- a/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
+++ b/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
@@ -16,9 +16,13 @@
package com.android.layoutlib.bridge.util;
+import com.android.tools.layoutlib.annotations.NotNull;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
/**
* Simpler wrapper around FileInputStream. This is used when the input stream represent
@@ -26,17 +30,22 @@ import java.io.FileNotFoundException;
* This is useful when the InputStream is created in a method but used in another that needs
* to know whether this is 9-patch or not, such as BitmapFactory.
*/
-public class NinePatchInputStream extends FileInputStream {
+public class NinePatchInputStream extends InputStream {
+ private final InputStream mDelegate;
private boolean mFakeMarkSupport = true;
+
public NinePatchInputStream(File file) throws FileNotFoundException {
- super(file);
+ mDelegate = new FileInputStream(file);
+ }
+
+ public NinePatchInputStream(@NotNull InputStream stream) {
+ mDelegate = stream;
}
@Override
public boolean markSupported() {
// this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
- return mFakeMarkSupport || super.markSupported();
-
+ return mFakeMarkSupport || mDelegate.markSupported();
}
public void disableFakeMarkSupport() {
@@ -44,4 +53,44 @@ public class NinePatchInputStream extends FileInputStream {
// we don't lie to them.
mFakeMarkSupport = false;
}
+
+ @Override
+ public int read() throws IOException {
+ return mDelegate.read();
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return mDelegate.read(b);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return mDelegate.read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return mDelegate.skip(n);
+ }
+
+ @Override
+ public int available() throws IOException {
+ return mDelegate.available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ mDelegate.close();
+ }
+
+ @Override
+ public void mark(int readlimit) {
+ mDelegate.mark(readlimit);
+ }
+
+ @Override
+ public void reset() throws IOException {
+ mDelegate.reset();
+ }
}
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java b/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
index 24395f27eb..67dd7c5bf1 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
@@ -17,6 +17,7 @@
package com.android.layoutlib.bridge.android;
import com.android.ide.common.rendering.api.ResourceNamespace;
+import com.android.ide.common.rendering.api.XmlParserFactory;
import com.android.layoutlib.bridge.impl.ParserFactory;
import org.junit.AfterClass;
@@ -28,6 +29,12 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
import static org.junit.Assert.assertEquals;
@@ -40,7 +47,6 @@ public class BridgeXmlBlockParserTest {
@Test
public void testXmlBlockParser() throws Exception {
-
XmlPullParser parser = ParserFactory.create(
getClass().getResourceAsStream("/com/android/layoutlib/testdata/layout1.xml"),
"layout1.xml");
@@ -126,13 +132,30 @@ public class BridgeXmlBlockParserTest {
ParserFactory.setParserFactory(null);
}
- private static class ParserFactoryImpl
- extends com.android.ide.common.rendering.api.ParserFactory {
+ private static class ParserFactoryImpl implements XmlParserFactory {
+ @Override
+ @Nullable
+ public XmlPullParser createXmlParserForPsiFile(@NonNull String fileName) {
+ return createXmlParserForFile(fileName);
+ }
- @NonNull
@Override
- public XmlPullParser createParser(String displayName) throws XmlPullParserException {
- return new KXmlParser();
+ @Nullable
+ public XmlPullParser createXmlParserForFile(@NonNull String fileName) {
+ try {
+ InputStream stream = new BufferedInputStream(new FileInputStream(fileName));
+ XmlPullParser parser = new KXmlParser();
+ parser.setInput(stream, null);
+ return parser;
+ } catch (FileNotFoundException | XmlPullParserException e) {
+ return null;
+ }
+ }
+
+ @Override
+ @NonNull
+ public XmlPullParser createXmlParser() {
+ throw new UnsupportedOperationException();
}
}
}
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index dac9570e9f..766cb11d28 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -23,6 +23,7 @@ import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams;
import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.ide.common.rendering.api.XmlParserFactory;
import com.android.internal.R;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.RenderParamsFlags;
@@ -41,9 +42,9 @@ import org.junit.After;
import org.junit.Test;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.AssetManager;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -776,9 +777,22 @@ public class RenderTests extends RenderTestBase {
// Setup
// Create the layout pull parser for our resources (empty.xml can not be part of the test
// app as it won't compile).
- ParserFactory.setParserFactory(new com.android.ide.common.rendering.api.ParserFactory() {
+ ParserFactory.setParserFactory(new XmlParserFactory() {
@Override
- public XmlPullParser createParser(String debugName) throws XmlPullParserException {
+ @Nullable
+ public XmlPullParser createXmlParserForPsiFile(@NonNull String fileName) {
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public XmlPullParser createXmlParserForFile(@NonNull String fileName) {
+ return null;
+ }
+
+ @Override
+ @NonNull
+ public XmlPullParser createXmlParser() {
return new KXmlParser();
}
});
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
index 37fc418d19..8056fa395b 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
@@ -21,7 +21,6 @@ import com.android.ide.common.rendering.api.ActionBarCallback;
import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.LayoutlibCallback;
-import com.android.ide.common.rendering.api.ParserFactory;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams.Key;
@@ -31,27 +30,32 @@ import com.android.utils.ILogger;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.HashMap;
import java.util.Map;
-import com.google.android.collect.Maps;
+import com.google.common.io.ByteStreams;
import static com.android.ide.common.rendering.api.ResourceNamespace.RES_AUTO;
public class LayoutLibTestCallback extends LayoutlibCallback {
-
private static final String PACKAGE_NAME = "com.android.layoutlib.test.myapplication";
- private final Map<Integer, ResourceReference> mProjectResources = Maps.newHashMap();
- private final Map<ResourceReference, Integer> mResources = Maps.newHashMap();
+ private final Map<Integer, ResourceReference> mProjectResources = new HashMap<>();
+ private final Map<ResourceReference, Integer> mResources = new HashMap<>();
private final ILogger mLog;
private final ActionBarCallback mActionBarCallback = new ActionBarCallback();
private final ClassLoader mModuleClassLoader;
@@ -153,16 +157,31 @@ public class LayoutLibTestCallback extends LayoutlibCallback {
return false;
}
- @NonNull
@Override
- public ParserFactory getParserFactory() {
- return new ParserFactory() {
- @NonNull
- @Override
- public XmlPullParser createParser(@Nullable String debugName) {
- return new KXmlParser();
- }
- };
+ @Nullable
+ public XmlPullParser createXmlParserForPsiFile(@NonNull String fileName) {
+ return createXmlParserForFile(fileName);
+ }
+
+ @Override
+ @Nullable
+ public XmlPullParser createXmlParserForFile(@NonNull String fileName) {
+ try (FileInputStream fileStream = new FileInputStream(fileName)) {
+ // Read data fully to memory to be able to close the file stream.
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ ByteStreams.copy(fileStream, byteOutputStream);
+ KXmlParser parser = new KXmlParser();
+ parser.setInput(new ByteArrayInputStream(byteOutputStream.toByteArray()), null);
+ return parser;
+ } catch (IOException | XmlPullParserException e) {
+ return null;
+ }
+ }
+
+ @Override
+ @NonNull
+ public XmlPullParser createXmlParser() {
+ return new KXmlParser();
}
@Override
diff --git a/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java b/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java
index c8483b8e5f..e893776952 100644
--- a/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java
+++ b/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java
@@ -139,9 +139,18 @@ public class RemoteLayoutlibCallbackAdapter implements RemoteLayoutlibCallback {
}
@Override
- public RemoteXmlPullParser getXmlFileParser(String fileName) {
+ public RemoteXmlPullParser getXmlParserForPsiFile(String fileName) {
try {
- return RemoteXmlPullParserAdapter.create(mDelegate.getXmlFileParser(fileName));
+ return RemoteXmlPullParserAdapter.create(mDelegate.getXmlParserForPsiFile(fileName));
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public RemoteXmlPullParser getXmlParserForFile(String fileName) {
+ try {
+ return RemoteXmlPullParserAdapter.create(mDelegate.getXmlParserForFile(fileName));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java b/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java
index 49c3764444..287de56fe9 100644
--- a/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java
+++ b/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java
@@ -60,5 +60,15 @@ public interface RemoteLayoutlibCallback extends Remote {
Path findClassPath(String name) throws RemoteException;
- RemoteXmlPullParser getXmlFileParser(String fileName) throws RemoteException;
+ /**
+ * @deprecated Use {@link #getXmlParserForPsiFile}.
+ */
+ @Deprecated
+ default RemoteXmlPullParser getXmlFileParser(String fileName) throws RemoteException {
+ return getXmlParserForPsiFile(fileName);
+ }
+
+ RemoteXmlPullParser getXmlParserForPsiFile(String fileName) throws RemoteException;
+
+ RemoteXmlPullParser getXmlParserForFile(String fileName) throws RemoteException;
}