More assetmanager work. Bakc to compile success state
diff --git a/annotations/build.gradle b/annotations/build.gradle
index 79c61f4..20ba4f5 100644
--- a/annotations/build.gradle
+++ b/annotations/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/integration-tests/dependency-on-stubs/build.gradle b/integration-tests/dependency-on-stubs/build.gradle
index acfd6a7..0ac99bc 100644
--- a/integration-tests/dependency-on-stubs/build.gradle
+++ b/integration-tests/dependency-on-stubs/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/libphonenumber/build.gradle b/integration-tests/libphonenumber/build.gradle
index 3a0dcb7..2511086 100644
--- a/integration-tests/libphonenumber/build.gradle
+++ b/integration-tests/libphonenumber/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/mockito-experimental/build.gradle b/integration-tests/mockito-experimental/build.gradle
index 3c32436..6b59f77 100644
--- a/integration-tests/mockito-experimental/build.gradle
+++ b/integration-tests/mockito-experimental/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/mockito/build.gradle b/integration-tests/mockito/build.gradle
index 08253a5..61cc9ae 100644
--- a/integration-tests/mockito/build.gradle
+++ b/integration-tests/mockito/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/powermock/build.gradle b/integration-tests/powermock/build.gradle
index 526dc26..cab7c55 100644
--- a/integration-tests/powermock/build.gradle
+++ b/integration-tests/powermock/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 apply plugin: RoboJavaModulePlugin
diff --git a/junit/build.gradle b/junit/build.gradle
index 884edf6..e930f90 100644
--- a/junit/build.gradle
+++ b/junit/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/processor/build.gradle b/processor/build.gradle
index c7a33f2..d473c9c 100644
--- a/processor/build.gradle
+++ b/processor/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/resources/build.gradle b/resources/build.gradle
index 77d7c02..df94923 100644
--- a/resources/build.gradle
+++ b/resources/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/resources/src/main/java/org/robolectric/res/android/Asset.java b/resources/src/main/java/org/robolectric/res/android/Asset.java
index a6ed59e..e9b2d7d 100644
--- a/resources/src/main/java/org/robolectric/res/android/Asset.java
+++ b/resources/src/main/java/org/robolectric/res/android/Asset.java
@@ -1,102 +1,127 @@
 package org.robolectric.res.android;
 
+import static org.robolectric.res.android.Util.ALOGI;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Class providing access to a read-only asset.  Asset objects are NOT thread-safe, and should not
+ * be shared across threads.
+ *
+ * transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-7.1.1_r13/include/androidfw/Asset.h
+ * and https://android.googlesource.com/platform/frameworks/base/+/android-7.1.1_r13/libs/androidfw/Asset.cpp
+ *
+ * Instances of this class provide read-only operations on a byte stream.
+ * Access may
+ * be optimized for streaming, random, or whole buffer modes.  All operations are supported
+ * regardless of how the file was opened, but some things will be less efficient.  [pass that
+ * in??]. "Asset" is the base class for all types of assets.  The classes below
+ * provide most of the implementation.  The AssetManager uses one of the static "create"
+ * functions defined here to create a new instance.
+ */
 public class Asset {
-//  static const bool kIsDebug = false;
+  //
+
+  //      public:
+//      virtual ~Asset(void) = default;
+//      static int32_t getGlobalCount();
+//      static String8 getAssetAllocations();
 //
-//  static Mutex gAssetLock;
-//  static int32_t gCount = 0;
-//  static Asset* gHead = NULL;
-//  static Asset* gTail = NULL;
-//
-//  void Asset::registerAsset(Asset* asset)
-//  {
-//    AutoMutex _l(gAssetLock);
-//    gCount++;
-//    asset->mNext = asset->mPrev = NULL;
-//    if (gTail == NULL) {
-//      gHead = gTail = asset;
-//    } else {
-//      asset->mPrev = gTail;
-//      gTail->mNext = asset;
-//      gTail = asset;
-//    }
-//
-//    if (kIsDebug) {
-//      ALOGI("Creating Asset %p #%d\n", asset, gCount);
-//    }
-//  }
-//
-//  void Asset::unregisterAsset(Asset* asset)
-//  {
-//    AutoMutex _l(gAssetLock);
-//    gCount--;
-//    if (gHead == asset) {
-//      gHead = asset->mNext;
-//    }
-//    if (gTail == asset) {
-//      gTail = asset->mPrev;
-//    }
-//    if (asset->mNext != NULL) {
-//      asset->mNext->mPrev = asset->mPrev;
-//    }
-//    if (asset->mPrev != NULL) {
-//      asset->mPrev->mNext = asset->mNext;
-//    }
-//    asset->mNext = asset->mPrev = NULL;
-//
-//    if (kIsDebug) {
-//      ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
-//    }
-//  }
-//
-//  int32_t Asset::getGlobalCount()
-//  {
-//    AutoMutex _l(gAssetLock);
-//    return gCount;
-//  }
-//
-//  String8 Asset::getAssetAllocations()
-//  {
+//    /* used when opening an asset */
+  enum AccessMode {
+    ACCESS_UNKNOWN,
+    /* read chunks, and seek forward and backward */
+    ACCESS_RANDOM,
+    /* read sequentially, with an occasional forward seek */
+    ACCESS_STREAMING,
+    /* caller plans to ask for a read-only buffer with all data */
+    ACCESS_BUFFER,
+  }
+
+//using namespace android;
+//#ifndef O_BINARY
+//# define O_BINARY 0
+//#endif
+private static final boolean kIsDebug = false;
+private static final Object gAssetLock = new Object();
+private static List<Asset> gAssets = new LinkedList<>();
+
+  private String8    mAssetSource;       // debug string
+
+  /* set the asset source string */
+  void setAssetSource(String8 path) {
+    mAssetSource = path;
+  }
+
+protected void registerAsset(Asset asset)
+{
+  int gCount = 0;
+    synchronized (gAssetLock) {
+      gAssets.add(asset);
+      gCount = gAssets.size();
+    }
+  if (kIsDebug) {
+    ALOGI("Creating Asset %p #%d\n", asset, gCount);
+  }
+
+}
+
+protected void unregisterAsset(Asset asset) {
+  int gCount = 0;
+  synchronized (gAssetLock) {
+    gAssets.remove(asset);
+    gCount = gAssets.size();
+  }
+  if (kIsDebug) {
+        ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
+    }
+}
+
+protected int getGlobalCount()
+{
+  synchronized (gAssetLock) {
+    return gAssets.size();
+  }
+}
+
+//String8 Asset::getAssetAllocations()
+//{
 //    AutoMutex _l(gAssetLock);
 //    String8 res;
 //    Asset* cur = gHead;
 //    while (cur != NULL) {
-//      if (cur->isAllocated()) {
-//        res.append("    ");
-//        res.append(cur->getAssetSource());
-//        off64_t size = (cur->getLength()+512)/1024;
-//        char buf[64];
-//        sprintf(buf, ": %dK\n", (int)size);
-//        res.append(buf);
-//      }
-//      cur = cur->mNext;
+//        if (cur->isAllocated()) {
+//            res.append("    ");
+//            res.append(cur->getAssetSource());
+//            off64_t size = (cur->getLength()+512)/1024;
+//            char buf[64];
+//            sprintf(buf, ": %dK\n", (int)size);
+//            res.append(buf);
+//        }
+//        cur = cur->mNext;
 //    }
-//
 //    return res;
-//  }
-//
-//  Asset::Asset(void)
+//}
+//Asset::Asset(void)
 //    : mAccessMode(ACCESS_UNKNOWN), mNext(NULL), mPrev(NULL)
-//  {
-//  }
-//
-///*
-// * Create a new Asset from a file on disk.  There is a fair chance that
-// * the file doesn't actually exist.
-// *
-// * We can use "mode" to decide how we want to go about it.
-// */
-///*static*/ Asset* Asset::createFromFile(const char* fileName, AccessMode mode)
-//  {
+//{
+//}
+/*
+ * Create a new Asset from a file on disk.  There is a fair chance that
+ * the file doesn't actually exist.
+ *
+ * We can use "mode" to decide how we want to go about it.
+ */
+static Asset createFromFile(String fileName, AccessMode mode)
+{
 //    _FileAsset* pAsset;
 //    status_t result;
 //    off64_t length;
 //    int fd;
-//
 //    fd = open(fileName, O_RDONLY | O_BINARY);
 //    if (fd < 0)
-//      return NULL;
-//
+//        return NULL;
 //    /*
 //     * Under Linux, the lseek fails if we actually opened a directory.  To
 //     * be correct we should test the file type explicitly, but since we
@@ -108,44 +133,43 @@
 //    length = lseek64(fd, 0, SEEK_END);
 //    if (length < 0) {
 //        ::close(fd);
-//      return NULL;
+//        return NULL;
 //    }
 //    (void) lseek64(fd, 0, SEEK_SET);
 //#else
 //    struct stat st;
 //    if (fstat(fd, &st) < 0) {
 //        ::close(fd);
-//    return NULL;
-//  }
-//
+//        return NULL;
+//    }
 //    if (!S_ISREG(st.st_mode)) {
 //        ::close(fd);
-//      return NULL;
+//        return NULL;
 //    }
 //#endif
-//
-//      pAsset = new _FileAsset;
+//    pAsset = new _FileAsset;
 //    result = pAsset->openChunk(fileName, fd, 0, length);
 //    if (result != NO_ERROR) {
-//      delete pAsset;
-//      return NULL;
+//        delete pAsset;
+//        return NULL;
 //    }
-//
 //    pAsset->mAccessMode = mode;
 //    return pAsset;
-//  }
-//
-//
-///*
-// * Create a new Asset from a compressed file on disk.  There is a fair chance
-// * that the file doesn't actually exist.
-// *
-// * We currently support gzip files.  We might want to handle .bz2 someday.
-// */
-///*static*/ Asset* Asset::createFromCompressedFile(const char* fileName,
-//      AccessMode mode)
-//  {
-//    _CompressedAsset* pAsset;
+  return null;
+}
+
+/*
+ * Create a new Asset from a compressed file on disk.  There is a fair chance
+ * that the file doesn't actually exist.
+ *
+ * We currently support gzip files.  We might want to handle .bz2 someday.
+ */
+
+static Asset createFromCompressedFile(String fileName,
+    AccessMode mode)
+{
+  return null;
+//    _CompressedAsset pAsset;
 //    status_t result;
 //    off64_t fileLen;
 //    bool scanResult;
@@ -153,268 +177,225 @@
 //    int method;
 //    long uncompressedLen, compressedLen;
 //    int fd;
-//
 //    fd = open(fileName, O_RDONLY | O_BINARY);
 //    if (fd < 0)
-//      return NULL;
-//
+//        return NULL;
 //    fileLen = lseek(fd, 0, SEEK_END);
 //    if (fileLen < 0) {
 //        ::close(fd);
-//      return NULL;
+//        return NULL;
 //    }
 //    (void) lseek(fd, 0, SEEK_SET);
-//
 //    /* want buffered I/O for the file scan; must dup so fclose() is safe */
 //    FILE* fp = fdopen(dup(fd), "rb");
 //    if (fp == NULL) {
 //        ::close(fd);
-//      return NULL;
+//        return NULL;
 //    }
-//
 //    unsigned long crc32;
 //    scanResult = ZipUtils::examineGzip(fp, &method, &uncompressedLen,
 //                    &compressedLen, &crc32);
 //    offset = ftell(fp);
 //    fclose(fp);
 //    if (!scanResult) {
-//      ALOGD("File '%s' is not in gzip format\n", fileName);
+//        ALOGD("File '%s' is not in gzip format\n", fileName);
 //        ::close(fd);
-//      return NULL;
+//        return NULL;
 //    }
-//
 //    pAsset = new _CompressedAsset;
 //    result = pAsset->openChunk(fd, offset, method, uncompressedLen,
-//        compressedLen);
+//                compressedLen);
 //    if (result != NO_ERROR) {
-//      delete pAsset;
-//      return NULL;
+//        delete pAsset;
+//        return NULL;
 //    }
-//
 //    pAsset->mAccessMode = mode;
 //    return pAsset;
-//  }
-//
-//
+}
 //#if 0
 ///*
 // * Create a new Asset from part of an open file.
 // */
 ///*static*/ Asset* Asset::createFromFileSegment(int fd, off64_t offset,
-//      size_t length, AccessMode mode)
-//  {
+//    size_t length, AccessMode mode)
+//{
 //    _FileAsset* pAsset;
 //    status_t result;
-//
 //    pAsset = new _FileAsset;
 //    result = pAsset->openChunk(NULL, fd, offset, length);
 //    if (result != NO_ERROR)
-//      return NULL;
-//
+//        return NULL;
 //    pAsset->mAccessMode = mode;
 //    return pAsset;
-//  }
-//
+//}
 ///*
 // * Create a new Asset from compressed data in an open file.
 // */
 ///*static*/ Asset* Asset::createFromCompressedData(int fd, off64_t offset,
-//      int compressionMethod, size_t uncompressedLen, size_t compressedLen,
-//      AccessMode mode)
-//  {
+//    int compressionMethod, size_t uncompressedLen, size_t compressedLen,
+//    AccessMode mode)
+//{
 //    _CompressedAsset* pAsset;
 //    status_t result;
-//
 //    pAsset = new _CompressedAsset;
 //    result = pAsset->openChunk(fd, offset, compressionMethod,
-//        uncompressedLen, compressedLen);
+//                uncompressedLen, compressedLen);
 //    if (result != NO_ERROR)
-//      return NULL;
-//
+//        return NULL;
 //    pAsset->mAccessMode = mode;
 //    return pAsset;
-//  }
+//}
 //#endif
-//
 ///*
 // * Create a new Asset from a memory mapping.
 // */
 ///*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap,
-//      AccessMode mode)
-//  {
+//    AccessMode mode)
+//{
 //    _FileAsset* pAsset;
 //    status_t result;
-//
 //    pAsset = new _FileAsset;
 //    result = pAsset->openChunk(dataMap);
 //    if (result != NO_ERROR)
-//      return NULL;
-//
+//        return NULL;
 //    pAsset->mAccessMode = mode;
 //    return pAsset;
-//  }
-//
+//}
 ///*
 // * Create a new Asset from compressed data in a memory mapping.
 // */
 ///*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
-//      size_t uncompressedLen, AccessMode mode)
-//  {
+//    size_t uncompressedLen, AccessMode mode)
+//{
 //    _CompressedAsset* pAsset;
 //    status_t result;
-//
 //    pAsset = new _CompressedAsset;
 //    result = pAsset->openChunk(dataMap, uncompressedLen);
 //    if (result != NO_ERROR)
-//      return NULL;
-//
+//        return NULL;
 //    pAsset->mAccessMode = mode;
 //    return pAsset;
-//  }
-//
-//
-//  /*
-//   * Do generic seek() housekeeping.  Pass in the offset/whence values from
-//   * the seek request, along with the current chunk offset and the chunk
-//   * length.
-//   *
-//   * Returns the new chunk offset, or -1 if the seek is illegal.
-//   */
-//  off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn)
-//  {
+//}
+///*
+// * Do generic seek() housekeeping.  Pass in the offset/whence values from
+// * the seek request, along with the current chunk offset and the chunk
+// * length.
+// *
+// * Returns the new chunk offset, or -1 if the seek is illegal.
+// */
+//off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn)
+//{
 //    off64_t newOffset;
-//
 //    switch (whence) {
-//      case SEEK_SET:
+//    case SEEK_SET:
 //        newOffset = offset;
 //        break;
-//      case SEEK_CUR:
+//    case SEEK_CUR:
 //        newOffset = curPosn + offset;
 //        break;
-//      case SEEK_END:
+//    case SEEK_END:
 //        newOffset = maxPosn + offset;
 //        break;
-//      default:
+//    default:
 //        ALOGW("unexpected whence %d\n", whence);
 //        // this was happening due to an off64_t size mismatch
 //        assert(false);
 //        return (off64_t) -1;
 //    }
-//
 //    if (newOffset < 0 || newOffset > maxPosn) {
-//      ALOGW("seek out of range: want %ld, end=%ld\n",
-//          (long) newOffset, (long) maxPosn);
-//      return (off64_t) -1;
+//        ALOGW("seek out of range: want %ld, end=%ld\n",
+//            (long) newOffset, (long) maxPosn);
+//        return (off64_t) -1;
 //    }
-//
 //    return newOffset;
-//  }
-//
-//
+//}
 ///*
 // * ===========================================================================
 // *      _FileAsset
 // * ===========================================================================
 // */
-//
 ///*
 // * Constructor.
 // */
-//  _FileAsset::_FileAsset(void)
+//_FileAsset::_FileAsset(void)
 //    : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
-//  {
+//{
 //    // Register the Asset with the global list here after it is fully constructed and its
 //    // vtable pointer points to this concrete type. b/31113965
 //    registerAsset(this);
-//  }
-//
+//}
 ///*
 // * Destructor.  Release resources.
 // */
-//  _FileAsset::~_FileAsset(void)
-//  {
+//_FileAsset::~_FileAsset(void)
+//{
 //    close();
-//
 //    // Unregister the Asset from the global list here before it is destructed and while its vtable
 //    // pointer still points to this concrete type. b/31113965
 //    unregisterAsset(this);
-//  }
-//
-//  /*
-//   * Operate on a chunk of an uncompressed file.
-//   *
-//   * Zero-length chunks are allowed.
-//   */
-//  status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
-//  {
+//}
+///*
+// * Operate on a chunk of an uncompressed file.
+// *
+// * Zero-length chunks are allowed.
+// */
+//status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
+//{
 //    assert(mFp == NULL);    // no reopen
 //    assert(mMap == NULL);
 //    assert(fd >= 0);
 //    assert(offset >= 0);
-//
 //    /*
 //     * Seek to end to get file length.
 //     */
 //    off64_t fileLength;
 //    fileLength = lseek64(fd, 0, SEEK_END);
 //    if (fileLength == (off64_t) -1) {
-//      // probably a bad file descriptor
-//      ALOGD("failed lseek (errno=%d)\n", errno);
-//      return UNKNOWN_ERROR;
+//        // probably a bad file descriptor
+//        ALOGD("failed lseek (errno=%d)\n", errno);
+//        return UNKNOWN_ERROR;
 //    }
-//
 //    if ((off64_t) (offset + length) > fileLength) {
-//      ALOGD("start (%ld) + len (%ld) > end (%ld)\n",
-//          (long) offset, (long) length, (long) fileLength);
-//      return BAD_INDEX;
+//        ALOGD("start (%ld) + len (%ld) > end (%ld)\n",
+//            (long) offset, (long) length, (long) fileLength);
+//        return BAD_INDEX;
 //    }
-//
 //    /* after fdopen, the fd will be closed on fclose() */
 //    mFp = fdopen(fd, "rb");
 //    if (mFp == NULL)
-//      return UNKNOWN_ERROR;
-//
+//        return UNKNOWN_ERROR;
 //    mStart = offset;
 //    mLength = length;
 //    assert(mOffset == 0);
-//
 //    /* seek the FILE* to the start of chunk */
 //    if (fseek(mFp, mStart, SEEK_SET) != 0) {
-//      assert(false);
+//        assert(false);
 //    }
-//
 //    mFileName = fileName != NULL ? strdup(fileName) : NULL;
-//
 //    return NO_ERROR;
-//  }
-//
-//  /*
-//   * Create the chunk from the map.
-//   */
-//  status_t _FileAsset::openChunk(FileMap* dataMap)
-//  {
+//}
+///*
+// * Create the chunk from the map.
+// */
+//status_t _FileAsset::openChunk(FileMap* dataMap)
+//{
 //    assert(mFp == NULL);    // no reopen
 //    assert(mMap == NULL);
 //    assert(dataMap != NULL);
-//
 //    mMap = dataMap;
 //    mStart = -1;            // not used
 //    mLength = dataMap->getDataLength();
 //    assert(mOffset == 0);
-//
 //    return NO_ERROR;
-//  }
-//
-//  /*
-//   * Read a chunk of data.
-//   */
-//  ssize_t _FileAsset::read(void* buf, size_t count)
-//  {
+//}
+///*
+// * Read a chunk of data.
+// */
+//ssize_t _FileAsset::read(void* buf, size_t count)
+//{
 //    size_t maxLen;
 //    size_t actual;
-//
 //    assert(mOffset >= 0 && mOffset <= mLength);
-//
 //    if (getAccessMode() == ACCESS_BUFFER) {
 //        /*
 //         * On first access, read or map the entire file.  The caller has
@@ -422,37 +403,33 @@
 //         * using the buffer or because what they're doing has appropriate
 //         * performance needs and access patterns.
 //         */
-//      if (mBuf == NULL)
-//        getBuffer(false);
+//        if (mBuf == NULL)
+//            getBuffer(false);
 //    }
-//
 //    /* adjust count if we're near EOF */
 //    maxLen = mLength - mOffset;
 //    if (count > maxLen)
-//      count = maxLen;
-//
+//        count = maxLen;
 //    if (!count)
-//      return 0;
-//
+//        return 0;
 //    if (mMap != NULL) {
 //        /* copy from mapped area */
-//      //printf("map read\n");
-//      memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
-//      actual = count;
+//        //printf("map read\n");
+//        memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
+//        actual = count;
 //    } else if (mBuf != NULL) {
 //        /* copy from buffer */
-//      //printf("buf read\n");
-//      memcpy(buf, (char*)mBuf + mOffset, count);
-//      actual = count;
+//        //printf("buf read\n");
+//        memcpy(buf, (char*)mBuf + mOffset, count);
+//        actual = count;
 //    } else {
 //        /* read from the file */
-//      //printf("file read\n");
-//      if (ftell(mFp) != mStart + mOffset) {
-//        ALOGE("Hosed: %ld != %ld+%ld\n",
-//            ftell(mFp), (long) mStart, (long) mOffset);
-//        assert(false);
-//      }
-//
+//        //printf("file read\n");
+//        if (ftell(mFp) != mStart + mOffset) {
+//            ALOGE("Hosed: %ld != %ld+%ld\n",
+//                ftell(mFp), (long) mStart, (long) mOffset);
+//            assert(false);
+//        }
 //        /*
 //         * This returns 0 on error or eof.  We need to use ferror() or feof()
 //         * to tell the difference, but we don't currently have those on the
@@ -460,68 +437,57 @@
 //         * file, so if we don't read the full amount we know something is
 //         * hosed.
 //         */
-//      actual = fread(buf, 1, count, mFp);
-//      if (actual == 0)        // something failed -- I/O error?
-//        return -1;
-//
-//      assert(actual == count);
+//        actual = fread(buf, 1, count, mFp);
+//        if (actual == 0)        // something failed -- I/O error?
+//            return -1;
+//        assert(actual == count);
 //    }
-//
 //    mOffset += actual;
 //    return actual;
-//  }
-//
-//  /*
-//   * Seek to a new position.
-//   */
-//  off64_t _FileAsset::seek(off64_t offset, int whence)
-//  {
+//}
+///*
+// * Seek to a new position.
+// */
+//off64_t _FileAsset::seek(off64_t offset, int whence)
+//{
 //    off64_t newPosn;
 //    off64_t actualOffset;
-//
 //    // compute new position within chunk
 //    newPosn = handleSeek(offset, whence, mOffset, mLength);
 //    if (newPosn == (off64_t) -1)
-//      return newPosn;
-//
+//        return newPosn;
 //    actualOffset = mStart + newPosn;
-//
 //    if (mFp != NULL) {
-//      if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
-//        return (off64_t) -1;
+//        if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
+//            return (off64_t) -1;
 //    }
-//
 //    mOffset = actualOffset - mStart;
 //    return mOffset;
-//  }
-//
-//  /*
-//   * Close the asset.
-//   */
-//  void _FileAsset::close(void)
-//  {
+//}
+///*
+// * Close the asset.
+// */
+//void _FileAsset::close(void)
+//{
 //    if (mMap != NULL) {
-//      delete mMap;
-//      mMap = NULL;
+//        delete mMap;
+//        mMap = NULL;
 //    }
 //    if (mBuf != NULL) {
-//      delete[] mBuf;
-//      mBuf = NULL;
+//        delete[] mBuf;
+//        mBuf = NULL;
 //    }
-//
 //    if (mFileName != NULL) {
-//      free(mFileName);
-//      mFileName = NULL;
+//        free(mFileName);
+//        mFileName = NULL;
 //    }
-//
 //    if (mFp != NULL) {
-//      // can only be NULL when called from destructor
-//      // (otherwise we would never return this object)
-//      fclose(mFp);
-//      mFp = NULL;
+//        // can only be NULL when called from destructor
+//        // (otherwise we would never return this object)
+//        fclose(mFp);
+//        mFp = NULL;
 //    }
-//  }
-//
+//}
 ///*
 // * Return a read-only pointer to a buffer.
 // *
@@ -531,289 +497,268 @@
 // * deal with it here.
 // */
 //const void* _FileAsset::getBuffer(bool wordAligned)
-//  Object getBuffer(boolean wordAligned)
-//  {
+//{
 //    /* subsequent requests just use what we did previously */
 //    if (mBuf != NULL)
-//      return mBuf;
+//        return mBuf;
 //    if (mMap != NULL) {
-//      if (!wordAligned) {
-//        return  mMap->getDataPtr();
-//      }
-//      return ensureAlignment(mMap);
+//        if (!wordAligned) {
+//            return  mMap->getDataPtr();
+//        }
+//        return ensureAlignment(mMap);
 //    }
-//
 //    assert(mFp != NULL);
-//
 //    if (mLength < kReadVsMapThreshold) {
-//      unsigned char* buf;
-//      long allocLen;
-//
+//        unsigned char* buf;
+//        long allocLen;
 //        /* zero-length files are allowed; not sure about zero-len allocs */
 //        /* (works fine with gcc + x86linux) */
-//      allocLen = mLength;
-//      if (mLength == 0)
-//        allocLen = 1;
-//
-//      buf = new unsigned char[allocLen];
-//      if (buf == NULL) {
-//        ALOGE("alloc of %ld bytes failed\n", (long) allocLen);
-//        return NULL;
-//      }
-//
-//      ALOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
-//      if (mLength > 0) {
-//        long oldPosn = ftell(mFp);
-//        fseek(mFp, mStart, SEEK_SET);
-//        if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
-//          ALOGE("failed reading %ld bytes\n", (long) mLength);
-//          delete[] buf;
-//          return NULL;
+//        allocLen = mLength;
+//        if (mLength == 0)
+//            allocLen = 1;
+//        buf = new unsigned char[allocLen];
+//        if (buf == NULL) {
+//            ALOGE("alloc of %ld bytes failed\n", (long) allocLen);
+//            return NULL;
 //        }
-//        fseek(mFp, oldPosn, SEEK_SET);
-//      }
-//
-//      ALOGV(" getBuffer: loaded into buffer\n");
-//
-//      mBuf = buf;
-//      return mBuf;
+//        ALOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
+//        if (mLength > 0) {
+//            long oldPosn = ftell(mFp);
+//            fseek(mFp, mStart, SEEK_SET);
+//            if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
+//                ALOGE("failed reading %ld bytes\n", (long) mLength);
+//                delete[] buf;
+//                return NULL;
+//            }
+//            fseek(mFp, oldPosn, SEEK_SET);
+//        }
+//        ALOGV(" getBuffer: loaded into buffer\n");
+//        mBuf = buf;
+//        return mBuf;
 //    } else {
-//      FileMap* map;
-//
-//      map = new FileMap;
-//      if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
-//        delete map;
-//        return NULL;
-//      }
-//
-//      ALOGV(" getBuffer: mapped\n");
-//
-//      mMap = map;
-//      if (!wordAligned) {
-//        return  mMap->getDataPtr();
-//      }
-//      return ensureAlignment(mMap);
+//        FileMap* map;
+//        map = new FileMap;
+//        if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
+//            delete map;
+//            return NULL;
+//        }
+//        ALOGV(" getBuffer: mapped\n");
+//        mMap = map;
+//        if (!wordAligned) {
+//            return  mMap->getDataPtr();
+//        }
+//        return ensureAlignment(mMap);
 //    }
-//  }
-
-//  int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
-//  {
+//}
+//int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
+//{
 //    if (mMap != NULL) {
 //        const char* fname = mMap->getFileName();
-//      if (fname == NULL) {
-//        fname = mFileName;
-//      }
-//      if (fname == NULL) {
-//        return -1;
-//      }
+//        if (fname == NULL) {
+//            fname = mFileName;
+//        }
+//        if (fname == NULL) {
+//            return -1;
+//        }
 //        *outStart = mMap->getDataOffset();
 //        *outLength = mMap->getDataLength();
-//      return open(fname, O_RDONLY | O_BINARY);
+//        return open(fname, O_RDONLY | O_BINARY);
 //    }
 //    if (mFileName == NULL) {
-//      return -1;
+//        return -1;
 //    }
 //    *outStart = mStart;
 //    *outLength = mLength;
 //    return open(mFileName, O_RDONLY | O_BINARY);
-//  }
-//
+//}
 //const void* _FileAsset::ensureAlignment(FileMap* map)
-//  {
+//{
 //    void* data = map->getDataPtr();
 //    if ((((size_t)data)&0x3) == 0) {
-//      // We can return this directly if it is aligned on a word
-//      // boundary.
-//      ALOGV("Returning aligned FileAsset %p (%s).", this,
-//          getAssetSource());
-//      return data;
+//        // We can return this directly if it is aligned on a word
+//        // boundary.
+//        ALOGV("Returning aligned FileAsset %p (%s).", this,
+//                getAssetSource());
+//        return data;
 //    }
 //    // If not aligned on a word boundary, then we need to copy it into
 //    // our own buffer.
 //    ALOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
-//        getAssetSource(), (int)mLength);
+//            getAssetSource(), (int)mLength);
 //    unsigned char* buf = new unsigned char[mLength];
 //    if (buf == NULL) {
-//      ALOGE("alloc of %ld bytes failed\n", (long) mLength);
-//      return NULL;
+//        ALOGE("alloc of %ld bytes failed\n", (long) mLength);
+//        return NULL;
 //    }
 //    memcpy(buf, data, mLength);
 //    mBuf = buf;
 //    return buf;
-//  }
-//
+//}
+/*
+ * ===========================================================================
+ *      _CompressedAsset
+ * ===========================================================================
+ */
+private static class _CompressedAsset extends Asset {
+  private long     mStart;         // offset to start of compressed data
+  private long     mCompressedLen; // length of the compressed data
+  private long     mUncompressedLen; // length of the uncompressed data
+  private long     mOffset;        // current offset, 0 == start of uncomp data
+  //FileMap*    mMap;           // for memory-mapped input
+  private int         mFd;            // for file input
+  //StreamingZipInflater mZipInflater;  // for streaming large compressed assets
+  private byte[]  mBuf;       // for getBuffer()
+
+/*
+ * Constructor.
+ */
+_CompressedAsset() {
+    mStart = 0;
+    mCompressedLen = 0;
+    mUncompressedLen = 0;
+    mOffset = 0;
+    // mMap = null;
+    mFd = -1;
+    //mZipInflater = null;
+    mBuf = null;
+
+    // Register the Asset with the global list here after it is fully constructed and its
+    // vtable pointer points to this concrete type. b/31113965
+    registerAsset(this);
+
+
+}
+/*
+ * Destructor.  Release resources.
+ */
+@Override
+public void finalize()
+  {
+    // close();
+    // Unregister the Asset from the global list here before it is destructed and while its vtable
+    // pointer still points to this concrete type. b/31113965
+    unregisterAsset(this);
+}
 ///*
-// * ===========================================================================
-// *      _CompressedAsset
-// * ===========================================================================
+// * Open a chunk of compressed data inside a file.
+// *
+// * This currently just sets up some values and returns.  On the first
+// * read, we expand the entire file into a buffer and return data from it.
 // */
-//
-///*
-// * Constructor.
-// */
-//  _CompressedAsset::_CompressedAsset(void)
-//    : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
-//  mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL)
-//  {
-//    // Register the Asset with the global list here after it is fully constructed and its
-//    // vtable pointer points to this concrete type. b/31113965
-//    registerAsset(this);
-//  }
-//
-///*
-// * Destructor.  Release resources.
-// */
-//  _CompressedAsset::~_CompressedAsset(void)
-//  {
-//    close();
-//
-//    // Unregister the Asset from the global list here before it is destructed and while its vtable
-//    // pointer still points to this concrete type. b/31113965
-//    unregisterAsset(this);
-//  }
-//
-//  /*
-//   * Open a chunk of compressed data inside a file.
-//   *
-//   * This currently just sets up some values and returns.  On the first
-//   * read, we expand the entire file into a buffer and return data from it.
-//   */
-//  status_t _CompressedAsset::openChunk(int fd, off64_t offset,
-//      int compressionMethod, size_t uncompressedLen, size_t compressedLen)
-//  {
+//status_t _CompressedAsset::openChunk(int fd, off64_t offset,
+//    int compressionMethod, size_t uncompressedLen, size_t compressedLen)
+//{
 //    assert(mFd < 0);        // no re-open
 //    assert(mMap == NULL);
 //    assert(fd >= 0);
 //    assert(offset >= 0);
 //    assert(compressedLen > 0);
-//
 //    if (compressionMethod != ZipFileRO::kCompressDeflated) {
-//      assert(false);
-//      return UNKNOWN_ERROR;
+//        assert(false);
+//        return UNKNOWN_ERROR;
 //    }
-//
 //    mStart = offset;
 //    mCompressedLen = compressedLen;
 //    mUncompressedLen = uncompressedLen;
 //    assert(mOffset == 0);
 //    mFd = fd;
 //    assert(mBuf == NULL);
-//
 //    if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
-//      mZipInflater = new StreamingZipInflater(mFd, offset, uncompressedLen, compressedLen);
+//        mZipInflater = new StreamingZipInflater(mFd, offset, uncompressedLen, compressedLen);
 //    }
-//
 //    return NO_ERROR;
-//  }
-//
-//  /*
-//   * Open a chunk of compressed data in a mapped region.
-//   *
-//   * Nothing is expanded until the first read call.
-//   */
-//  status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen)
-//  {
+//}
+///*
+// * Open a chunk of compressed data in a mapped region.
+// *
+// * Nothing is expanded until the first read call.
+// */
+//status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen)
+//{
 //    assert(mFd < 0);        // no re-open
 //    assert(mMap == NULL);
 //    assert(dataMap != NULL);
-//
 //    mMap = dataMap;
 //    mStart = -1;        // not used
 //    mCompressedLen = dataMap->getDataLength();
 //    mUncompressedLen = uncompressedLen;
 //    assert(mOffset == 0);
-//
 //    if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
-//      mZipInflater = new StreamingZipInflater(dataMap, uncompressedLen);
+//        mZipInflater = new StreamingZipInflater(dataMap, uncompressedLen);
 //    }
 //    return NO_ERROR;
-//  }
-//
-//  /*
-//   * Read data from a chunk of compressed data.
-//   *
-//   * [For now, that's just copying data out of a buffer.]
-//   */
-//  ssize_t _CompressedAsset::read(void* buf, size_t count)
-//  {
+//}
+///*
+// * Read data from a chunk of compressed data.
+// *
+// * [For now, that's just copying data out of a buffer.]
+// */
+//ssize_t _CompressedAsset::read(void* buf, size_t count)
+//{
 //    size_t maxLen;
 //    size_t actual;
-//
 //    assert(mOffset >= 0 && mOffset <= mUncompressedLen);
-//
 //    /* If we're relying on a streaming inflater, go through that */
 //    if (mZipInflater) {
-//      actual = mZipInflater->read(buf, count);
+//        actual = mZipInflater->read(buf, count);
 //    } else {
-//      if (mBuf == NULL) {
-//        if (getBuffer(false) == NULL)
-//          return -1;
-//      }
-//      assert(mBuf != NULL);
-//
+//        if (mBuf == NULL) {
+//            if (getBuffer(false) == NULL)
+//                return -1;
+//        }
+//        assert(mBuf != NULL);
 //        /* adjust count if we're near EOF */
-//      maxLen = mUncompressedLen - mOffset;
-//      if (count > maxLen)
-//        count = maxLen;
-//
-//      if (!count)
-//        return 0;
-//
+//        maxLen = mUncompressedLen - mOffset;
+//        if (count > maxLen)
+//            count = maxLen;
+//        if (!count)
+//            return 0;
 //        /* copy from buffer */
-//      //printf("comp buf read\n");
-//      memcpy(buf, (char*)mBuf + mOffset, count);
-//      actual = count;
+//        //printf("comp buf read\n");
+//        memcpy(buf, (char*)mBuf + mOffset, count);
+//        actual = count;
 //    }
-//
 //    mOffset += actual;
 //    return actual;
-//  }
-//
-//  /*
-//   * Handle a seek request.
-//   *
-//   * If we're working in a streaming mode, this is going to be fairly
-//   * expensive, because it requires plowing through a bunch of compressed
-//   * data.
-//   */
-//  off64_t _CompressedAsset::seek(off64_t offset, int whence)
-//  {
+//}
+///*
+// * Handle a seek request.
+// *
+// * If we're working in a streaming mode, this is going to be fairly
+// * expensive, because it requires plowing through a bunch of compressed
+// * data.
+// */
+//off64_t _CompressedAsset::seek(off64_t offset, int whence)
+//{
 //    off64_t newPosn;
-//
 //    // compute new position within chunk
 //    newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen);
 //    if (newPosn == (off64_t) -1)
-//      return newPosn;
-//
+//        return newPosn;
 //    if (mZipInflater) {
-//      mZipInflater->seekAbsolute(newPosn);
+//        mZipInflater->seekAbsolute(newPosn);
 //    }
 //    mOffset = newPosn;
 //    return mOffset;
-//  }
-//
-//  /*
-//   * Close the asset.
-//   */
-//  void _CompressedAsset::close(void)
-//  {
+//}
+///*
+// * Close the asset.
+// */
+//void _CompressedAsset::close(void)
+//{
 //    if (mMap != NULL) {
-//      delete mMap;
-//      mMap = NULL;
+//        delete mMap;
+//        mMap = NULL;
 //    }
-//
 //    delete[] mBuf;
 //    mBuf = NULL;
-//
 //    delete mZipInflater;
 //    mZipInflater = NULL;
-//
 //    if (mFd > 0) {
 //        ::close(mFd);
-//      mFd = -1;
+//        mFd = -1;
 //    }
-//  }
-//
+//}
 ///*
 // * Get a pointer to a read-only buffer of data.
 // *
@@ -821,56 +766,47 @@
 // * buffer.
 // */
 //const void* _CompressedAsset::getBuffer(bool)
-//  {
+//{
 //    unsigned char* buf = NULL;
-//
 //    if (mBuf != NULL)
-//      return mBuf;
-//
+//        return mBuf;
 //    /*
 //     * Allocate a buffer and read the file into it.
 //     */
 //    buf = new unsigned char[mUncompressedLen];
 //    if (buf == NULL) {
-//      ALOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
+//        ALOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
 //        goto bail;
 //    }
-//
 //    if (mMap != NULL) {
-//      if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf,
-//          mUncompressedLen, mCompressedLen))
+//        if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf,
+//                mUncompressedLen, mCompressedLen))
 //            goto bail;
 //    } else {
-//      assert(mFd >= 0);
-//
+//        assert(mFd >= 0);
 //        /*
 //         * Seek to the start of the compressed data.
 //         */
-//      if (lseek(mFd, mStart, SEEK_SET) != mStart)
+//        if (lseek(mFd, mStart, SEEK_SET) != mStart)
 //            goto bail;
-//
 //        /*
 //         * Expand the data into it.
 //         */
-//      if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
-//          mCompressedLen))
+//        if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
+//                mCompressedLen))
 //            goto bail;
 //    }
-//
 //    /*
 //     * Success - now that we have the full asset in RAM we
 //     * no longer need the streaming inflater
 //     */
 //    delete mZipInflater;
 //    mZipInflater = NULL;
-//
 //    mBuf = buf;
 //    buf = NULL;
-//
-//    bail:
+//bail:
 //    delete[] buf;
 //    return mBuf;
-//  }
 //
-
+}
 }
diff --git a/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java b/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java
index 2194e70..0cea798 100644
--- a/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java
+++ b/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java
@@ -1,5 +1,6 @@
 package org.robolectric.res.android;
 
+import static org.robolectric.res.android.Util.ALOGV;
 import static org.robolectric.res.android.Util.ALOGW;
 import static org.robolectric.res.android.Util.ATRACE_CALL;
 import static org.robolectric.res.android.Util.LOG_FATAL_IF;
@@ -9,17 +10,30 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
+import javax.annotation.Nullable;
+import org.robolectric.res.android.Asset.AccessMode;
 import org.robolectric.res.android.CppAssetManager.FileType;
 
 // transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-7.1.1_r13/libs/androidfw/AssetManager.cpp
 public class CppAssetManager {
 
   enum FileType {
-    kFileTypeRegular
+    kFileTypeUnknown,
+    kFileTypeNonexistent,       // i.e. ENOENT
+    kFileTypeRegular,
+    kFileTypeDirectory,
+    kFileTypeCharDev,
+    kFileTypeBlockDev,
+    kFileTypeFifo,
+    kFileTypeSymlink,
+    kFileTypeSocket,
   }
 
 
@@ -31,10 +45,10 @@
 
 
     public asset_path() {
-      this("", FileType.kFileTypeRegular, "", false, false);
+      this(new String8(), FileType.kFileTypeRegular, "", false, false);
     }
 
-    public asset_path(String path, FileType fileType, String idmap,
+    public asset_path(String8 path, FileType fileType, String idmap,
         boolean isSystemOverlay,
         boolean isSystemAsset) {
       this.path = path;
@@ -44,7 +58,7 @@
       this.isSystemAsset = isSystemAsset;
     }
 
-    String path;
+    String8 path;
     FileType type;
     String idmap;
     boolean isSystemOverlay;
@@ -53,7 +67,8 @@
 
   private final Object   mLock = new Object();
 
-//  ZipSet          mZipSet;
+  //ZipSet          mZipSet;
+  Object mZipSet;
 
   private final List<asset_path> mAssetPaths = new ArrayList<>();
   private String mLocale;
@@ -64,14 +79,17 @@
 
 //  static final boolean kIsDebug = false;
 //  
-//  static final char* kAssetsRoot = "assets";
-//  static final char* kAppZipName = NULL; //"classes.jar";
+  static final String kAssetsRoot = "assets";
+  static final String kAppZipName = null; //"classes.jar";
 //  static final char* kSystemAssets = "framework/framework-res.apk";
 //  static final char* kResourceCache = "resource-cache";
 //  
 //  static final char* kExcludeExtension = ".EXCLUDE";
 //  
-//  static Asset* final kExcludedAsset = (Asset*) 0xd000000d;
+
+  // TODO: figure out how to translate this to Java
+  // static Asset final kExcludedAsset = (Asset*) 0xd000000d;
+  static final Asset kExcludedAsset = null;
 //  
 //  static volatile int gCount = 0;
 //  
@@ -162,65 +180,68 @@
 //      delete[] mLocale;
 //  }
 //  
-//  boolean addAssetPath(
-//          final String8& path, int* cookie, boolean appAsLib, boolean isSystemAsset) {
-//      AutoMutex _l(mLock);
-//  
-//      asset_path ap;
-//  
-//      String8 realPath(path);
-//      if (kAppZipName) {
-//          realPath.appendPath(kAppZipName);
-//      }
-//      ap.type = .getFileType(realPath.string());
-//      if (ap.type == kFileTypeRegular) {
-//          ap.path = realPath;
-//      } else {
-//          ap.path = path;
-//          ap.type = .getFileType(path.string());
-//          if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
-//              ALOGW("Asset path %s is neither a directory nor file (type=%d).",
-//                   path.string(), (int)ap.type);
-//              return false;
-//          }
-//      }
-//  
-//      // Skip if we have it already.
-//      for (int i=0; i<mAssetPaths.size(); i++) {
-//          if (mAssetPaths[i].path == ap.path) {
-//              if (cookie) {
-//                  *cookie = static_cast<int>(i+1);
-//              }
-//              return true;
-//          }
-//      }
-//  
-//      ALOGV("In %p Asset %s path: %s", this,
-//           ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
-//  
-//      ap.isSystemAsset = isSystemAsset;
-//      mAssetPaths.add(ap);
-//  
-//      // new paths are always added at the end
-//      if (cookie) {
-//          *cookie = static_cast<int>(mAssetPaths.size());
-//      }
-//  
-//  #ifdef __ANDROID__
-//      // Load overlays, if any
-//      asset_path oap;
-//      for (int idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
-//          oap.isSystemAsset = isSystemAsset;
-//          mAssetPaths.add(oap);
-//      }
-//  #endif
-//  
-//      if (mResources != NULL) {
-//          appendPathToResTable(ap, appAsLib);
-//      }
-//  
-//      return true;
-//  }
+  boolean addAssetPath(
+          final String8 path, @Nullable  Ref<Integer> cookie, boolean appAsLib, boolean isSystemAsset) {
+      synchronized (mLock) {
+
+        asset_path ap = new asset_path();
+
+        String8 realPath = path;
+        if (kAppZipName != null) {
+          realPath.appendPath(kAppZipName);
+        }
+        ap.type = getFileType(realPath.string());
+        if (ap.type == FileType.kFileTypeRegular) {
+          ap.path = realPath;
+        } else {
+          ap.path = path;
+          ap.type = getFileType(path.string());
+          if (ap.type != FileType.kFileTypeDirectory && ap.type != FileType.kFileTypeRegular) {
+            ALOGW("Asset path %s is neither a directory nor file (type=%s).",
+                path.toString(), ap.type.name());
+            return false;
+          }
+        }
+
+        // Skip if we have it already.
+        for (int i = 0; i < mAssetPaths.size(); i++) {
+          if (mAssetPaths.get(i).path.equals(ap.path)) {
+            if (cookie != null) {
+                  cookie.set(i + 1);
+            }
+            return true;
+          }
+        }
+
+        ALOGV("In %p Asset %s path: %s", this,
+            ap.type == FileType.kFileTypeDirectory ? "dir" : "zip", ap.path.toString());
+
+        ap.isSystemAsset = isSystemAsset;
+        mAssetPaths.add(ap);
+
+        // new paths are always added at the end
+        if (cookie != null) {
+          cookie.set(mAssetPaths.size());
+        }
+
+        // TODO: implement this?
+  //#ifdef __ANDROID__
+        // Load overlays, if any
+        //asset_path oap;
+        //for (int idx = 0; mZipSet.getOverlay(ap.path, idx, & oap)
+        //  ; idx++){
+        //  oap.isSystemAsset = isSystemAsset;
+        //  mAssetPaths.add(oap);
+       // }
+  //#endif
+
+        if (mResources != null) {
+          appendPathToResTable(ap, appAsLib);
+        }
+
+        return true;
+      }
+  }
 //  
 //  boolean addOverlayPath(final String8& packagePath, int* cookie)
 //  {
@@ -381,44 +402,44 @@
 //      *outConfig = *mConfig;
 //  }
 //  
-//  /*
-//   * Open an asset.
-//   *
-//   * The data could be in any asset path. Each asset path could be:
-//   *  - A directory on disk.
-//   *  - A Zip archive, uncompressed or compressed.
-//   *
-//   * If the file is in a directory, it could have a .gz suffix, meaning it is compressed.
-//   *
-//   * We should probably reject requests for "illegal" filenames, e.g. those
-//   * with illegal characters or "../" backward relative paths.
-//   */
-//  Asset* open(final char* fileName, AccessMode mode)
-//  {
-//      AutoMutex _l(mLock);
-//  
-//      LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
-//  
-//      String8 assetName(kAssetsRoot);
-//      assetName.appendPath(fileName);
-//  
-//      /*
-//       * For each top-level asset path, search for the asset.
-//       */
-//  
-//      int i = mAssetPaths.size();
-//      while (i > 0) {
-//          i--;
-//          ALOGV("Looking for asset '%s' in '%s'\n",
-//                  assetName.string(), mAssetPaths.itemAt(i).path.string());
-//          Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i));
-//          if (pAsset != NULL) {
-//              return pAsset != kExcludedAsset ? pAsset : NULL;
-//          }
-//      }
-//  
-//      return NULL;
-//  }
+  /*
+   * Open an asset.
+   *
+   * The data could be in any asset path. Each asset path could be:
+   *  - A directory on disk.
+   *  - A Zip archive, uncompressed or compressed.
+   *
+   * If the file is in a directory, it could have a .gz suffix, meaning it is compressed.
+   *
+   * We should probably reject requests for "illegal" filenames, e.g. those
+   * with illegal characters or "../" backward relative paths.
+   */
+  Asset open(final String fileName, AccessMode mode)
+  {
+      synchronized (mLock) {
+
+        LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+        String8 assetName = new String8(kAssetsRoot);
+        assetName.appendPath(fileName);
+      /*
+       * For each top-level asset path, search for the asset.
+       */
+        int i = mAssetPaths.size();
+        while (i > 0) {
+          i--;
+          ALOGV("Looking for asset '%s' in '%s'\n",
+              assetName.string(), mAssetPaths.get(i).path.string());
+          Asset pAsset = openNonAssetInPathLocked(assetName.string(), mode,
+              mAssetPaths.get(i));
+          if (pAsset != null) {
+            return Objects.equals(pAsset, kExcludedAsset) ? null  : pAsset;
+          }
+        }
+
+        return null;
+      }
+  }
 //  
 //  /*
 //   * Open a non-asset file as if it were an asset.
@@ -471,30 +492,30 @@
 //      return NULL;
 //  }
 //  
-//  /*
-//   * Get the type of a file in the asset namespace.
-//   *
-//   * This currently only works for regular files.  All others (including
-//   * directories) will return kFileTypeNonexistent.
-//   */
-//  FileType getFileType(final char* fileName)
-//  {
-//      Asset* pAsset = NULL;
-//  
-//      /*
-//       * Open the asset.  This is less efficient than simply finding the
-//       * file, but it's not too bad (we don't uncompress or mmap data until
-//       * the first read() call).
-//       */
-//      pAsset = open(fileName, Asset.ACCESS_STREAMING);
-//      delete pAsset;
-//  
-//      if (pAsset == NULL) {
-//          return kFileTypeNonexistent;
-//      } else {
-//          return kFileTypeRegular;
-//      }
-//  }
+  /*
+   * Get the type of a file in the asset namespace.
+   *
+   * This currently only works for regular files.  All others (including
+   * directories) will return kFileTypeNonexistent.
+   */
+  FileType getFileType(final String fileName)
+  {
+      Asset pAsset = null;
+
+      /*
+       * Open the asset.  This is less efficient than simply finding the
+       * file, but it's not too bad (we don't uncompress or mmap data until
+       * the first read() call).
+       */
+      pAsset = open(fileName, Asset.AccessMode.ACCESS_STREAMING);
+      // delete pAsset;
+
+      if (pAsset == null) {
+          return FileType.kFileTypeNonexistent;
+      } else {
+          return FileType.kFileTypeRegular;
+      }
+  }
 
   boolean appendPathToResTable(final asset_path ap, boolean appAsLib) {
     URL resource = getClass().getResource("/resources.ap_");
@@ -746,40 +767,40 @@
 //      }
 //  }
 //  
-//  /*
-//   * Open a non-asset file as if it were an asset, searching for it in the
-//   * specified app.
-//   *
-//   * Pass in a NULL values for "appName" if the common app directory should
-//   * be used.
-//   */
-//  Asset* openNonAssetInPathLocked(final char* fileName, AccessMode mode,
-//      final asset_path& ap)
-//  {
-//      Asset* pAsset = NULL;
-//  
-//      /* look at the filesystem on disk */
-//      if (ap.type == kFileTypeDirectory) {
-//          String8 path(ap.path);
-//          path.appendPath(fileName);
-//  
-//          pAsset = openAssetFromFileLocked(path, mode);
-//  
-//          if (pAsset == NULL) {
-//              /* try again, this time with ".gz" */
-//              path.append(".gz");
-//              pAsset = openAssetFromFileLocked(path, mode);
-//          }
-//  
-//          if (pAsset != NULL) {
-//              //printf("FOUND NA '%s' on disk\n", fileName);
-//              pAsset.setAssetSource(path);
-//          }
-//  
-//      /* look inside the zip file */
-//      } else {
-//          String8 path(fileName);
-//  
+  /*
+   * Open a non-asset file as if it were an asset, searching for it in the
+   * specified app.
+   *
+   * Pass in a NULL values for "appName" if the common app directory should
+   * be used.
+   */
+  Asset openNonAssetInPathLocked(final String fileName, AccessMode mode,
+      final asset_path ap)
+  {
+      Asset pAsset = null;
+
+      /* look at the filesystem on disk */
+      if (ap.type == FileType.kFileTypeDirectory) {
+          String8 path = new String8(ap.path);
+          path.appendPath(fileName);
+
+          pAsset = openAssetFromFileLocked(path, mode);
+
+          if (pAsset == null) {
+              /* try again, this time with ".gz" */
+              path.append(".gz");
+              pAsset = openAssetFromFileLocked(path, mode);
+          }
+
+          if (pAsset != null) {
+              //printf("FOUND NA '%s' on disk\n", fileName);
+              pAsset.setAssetSource(path);
+          }
+
+      /* look inside the zip file */
+      } else {
+//          String8 path = new String8(fileName);
+//
 //          /* check the appropriate Zip file */
 //          ZipFileRO* pZip = getZipFileLocked(ap);
 //          if (pZip != NULL) {
@@ -791,17 +812,17 @@
 //                  pZip.releaseEntry(entry);
 //              }
 //          }
-//  
+//
 //          if (pAsset != NULL) {
 //              /* create a "source" name, for debug/display */
 //              pAsset.setAssetSource(
 //                      createZipSourceNameLocked(ZipSet.getPathName(ap.path.string()), String8(""),
 //                                                  String8(fileName)));
 //          }
-//      }
-//  
-//      return pAsset;
-//  }
+      }
+
+      return pAsset;
+  }
 //  
 //  /*
 //   * Create a "source name" for a file from a Zip archive.
@@ -840,33 +861,33 @@
 //      return mZipSet.getZip(ap.path);
 //  }
 //  
-//  /*
-//   * Try to open an asset from a file on disk.
-//   *
-//   * If the file is compressed with gzip, we seek to the start of the
-//   * deflated data and pass that in (just like we would for a Zip archive).
-//   *
-//   * For uncompressed data, we may already have an mmap()ed version sitting
-//   * around.  If so, we want to hand that to the Asset instead.
-//   *
-//   * This returns NULL if the file doesn't exist, couldn't be opened, or
-//   * claims to be a ".gz" but isn't.
-//   */
-//  Asset* openAssetFromFileLocked(final String8& pathName,
-//      AccessMode mode)
-//  {
-//      Asset* pAsset = NULL;
-//  
-//      if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) {
-//          //printf("TRYING '%s'\n", (final char*) pathName);
-//          pAsset = Asset.createFromCompressedFile(pathName.string(), mode);
-//      } else {
-//          //printf("TRYING '%s'\n", (final char*) pathName);
-//          pAsset = Asset.createFromFile(pathName.string(), mode);
-//      }
-//  
-//      return pAsset;
-//  }
+  /*
+   * Try to open an asset from a file on disk.
+   *
+   * If the file is compressed with gzip, we seek to the start of the
+   * deflated data and pass that in (just like we would for a Zip archive).
+   *
+   * For uncompressed data, we may already have an mmap()ed version sitting
+   * around.  If so, we want to hand that to the Asset instead.
+   *
+   * This returns NULL if the file doesn't exist, couldn't be opened, or
+   * claims to be a ".gz" but isn't.
+   */
+  Asset openAssetFromFileLocked(final String8 pathName,
+      AccessMode mode)
+  {
+      Asset pAsset = null;
+
+      if (pathName.getPathExtension().toLowerCase().equals(".gz")) {
+          //printf("TRYING '%s'\n", (final char*) pathName);
+          pAsset = Asset.createFromCompressedFile(pathName.string(), mode);
+      } else {
+          //printf("TRYING '%s'\n", (final char*) pathName);
+          pAsset = Asset.createFromFile(pathName.string(), mode);
+      }
+
+      return pAsset;
+  }
 //  
 //  /*
 //   * Given an entry in a Zip archive, create a new Asset object.
diff --git a/resources/src/main/java/org/robolectric/res/android/Type.java b/resources/src/main/java/org/robolectric/res/android/DataType.java
similarity index 88%
rename from resources/src/main/java/org/robolectric/res/android/Type.java
rename to resources/src/main/java/org/robolectric/res/android/DataType.java
index 1554877..75d6794 100644
--- a/resources/src/main/java/org/robolectric/res/android/Type.java
+++ b/resources/src/main/java/org/robolectric/res/android/DataType.java
@@ -7,7 +7,7 @@
 import java.util.Map;
 
 /** Resource type codes. */
-public enum Type {
+public enum DataType {
   /** {@code data} is either 0 (undefined) or 1 (empty). */
   NULL(0x00),
   /** {@code data} holds a {@link ResourceTableChunk} entry reference. */
@@ -41,17 +41,17 @@
 
   private final byte code;
 
-  private static final Map<Byte, Type> FROM_BYTE;
+  private static final Map<Byte, DataType> FROM_BYTE;
 
   static {
-    Builder<Byte, Type> builder = ImmutableMap.builder();
-    for (Type type : values()) {
+    Builder<Byte, DataType> builder = ImmutableMap.builder();
+    for (DataType type : values()) {
       builder.put(type.code(), type);
     }
     FROM_BYTE = builder.build();
   }
 
-  Type(int code) {
+  DataType(int code) {
     this.code = UnsignedBytes.checkedCast(code);
   }
 
@@ -59,7 +59,7 @@
     return code;
   }
 
-  public static Type fromCode(byte code) {
+  public static DataType fromCode(byte code) {
     return Preconditions.checkNotNull(FROM_BYTE.get(code), "Unknown resource type: %s", code);
   }
 }
diff --git a/resources/src/main/java/org/robolectric/res/android/ResTable.java b/resources/src/main/java/org/robolectric/res/android/ResTable.java
index 790f399..7b5586b 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResTable.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResTable.java
@@ -398,6 +398,42 @@
     return entry.get()._package_.header.index;
   }
 
+  public final int resolveReference(ResValue value, int blockIndex,
+      Ref<Integer> outLastRef, Ref<Integer> inoutTypeSpecFlags,
+      Ref<ResTableConfig> outConfig)
+  {
+    int count=0;
+    while (blockIndex >= 0 && value.dataType == DataType.REFERENCE.code()
+        && value.data != 0 && count < 20) {
+      if (outLastRef.get() == null) {
+        outLastRef.set(value.data);
+      }
+      Ref<Integer> newFlags = new Ref<>(0);
+      final int newIndex = getResource(value.data, new Ref<>(value), true, 0,
+          newFlags, outConfig);
+      if (newIndex == BAD_INDEX) {
+        return BAD_INDEX;
+      }
+      if (kDebugTableTheme) {
+        Util.ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
+            value.data, (int)newIndex, (int)value.dataType, value.data);
+      }
+      //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
+      if (inoutTypeSpecFlags != null) {
+        inoutTypeSpecFlags.set(inoutTypeSpecFlags.get() | newFlags.get());
+      }
+      if (newIndex < 0) {
+        // This can fail if the resource being referenced is a style...
+        // in this case, just return the reference, and expect the
+        // caller to deal with.
+        return blockIndex;
+      }
+      blockIndex = newIndex;
+      count++;
+    }
+    return blockIndex;
+  }
+
   Entry getEntry(int resId, String qualifiers) {
     return getEntry(ResourceIds.getPackageIdentifier(resId),
         ResourceIds.getTypeIdentifier(resId),
@@ -599,6 +635,10 @@
     this.parameters = parameters;
   }
 
+  public int getTableCookie(int index) {
+    return mHeaders.get(index).cookie;
+  }
+
   // A group of objects describing a particular resource package.
   // The first in 'package' is always the root object (from the resource
   // table that defined the package); the ones after are skins on top of it.
@@ -625,7 +665,7 @@
 //      clearBagCache();
 //      final int numTypes = types.size();
 //      for (int i = 0; i < numTypes; i++) {
-//        final List<Type> typeList = types.get(i);
+//        final List<DataType> typeList = types.get(i);
 //        final int numInnerTypes = typeList.size();
 //        for (int j = 0; j < numInnerTypes; j++) {
 //          if (typeList.get(j)._package_.owner == owner) {
@@ -652,7 +692,7 @@
 //        if (kDebugTableNoisy) {
 //          printf("type=%zu\n", i);
 //        }
-//        final List<Type> typeList = types.get(i);
+//        final List<DataType> typeList = types.get(i);
 //        if (!typeList.isEmpty()) {
 //          TypeCacheEntry cacheEntry = typeCacheEntries.editItemAt(i);
 //
@@ -773,7 +813,7 @@
     StringPoolRef keyStr;
   }
 
-  // struct ResTable::Type
+  // struct ResTable::DataType
   public static class Type {
 
     final Header header;
diff --git a/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java b/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java
index a5decfa..66c0d64 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java
@@ -341,7 +341,7 @@
 
   public int orientation;
   int touchscreen;
-  int density;
+  public int density;
   int keyboard;
   int navigation;
   int inputFlags;
diff --git a/resources/src/main/java/org/robolectric/res/android/ResTableType.java b/resources/src/main/java/org/robolectric/res/android/ResTableType.java
index 2a5bfab..05e3a30 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResTableType.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResTableType.java
@@ -26,7 +26,7 @@
  * It would be nice to have an additional ordered index of entries, so
  * we can do a binary search if trying to find a resource by string name.
  *
- * Type from androidfw/include/androidfw/ResourceTypes.h
+ * DataType from androidfw/include/androidfw/ResourceTypes.h
  */
 public class ResTableType {
     public static final int NO_ENTRY = 0xFFFFFFFF;
@@ -39,7 +39,7 @@
 
     public ResChunkHeader header;
 
-    // The type identifier this chunk is holding.  Type IDs start
+    // The type identifier this chunk is holding.  DataType IDs start
     // at 1 (corresponding to the value of the type bits in a
     // resource identifier).  0 is invalid.
     public byte id;
diff --git a/resources/src/main/java/org/robolectric/res/android/ResValue.java b/resources/src/main/java/org/robolectric/res/android/ResValue.java
index 7297a98..b5abeaf 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResValue.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResValue.java
@@ -9,6 +9,7 @@
  * <p>frameworks/base/include/androidfw/ResourceTypes.h (struct Res_value)
  */
 public final class ResValue {
+  // must be one of DataType
   public int dataType;
   public int data;
 
diff --git a/resources/src/main/java/org/robolectric/res/android/String8.java b/resources/src/main/java/org/robolectric/res/android/String8.java
new file mode 100644
index 0000000..a0311c0
--- /dev/null
+++ b/resources/src/main/java/org/robolectric/res/android/String8.java
@@ -0,0 +1,406 @@
+package org.robolectric.res.android;
+
+import java.io.File;
+
+// transliterated from https://android.googlesource.com/platform/system/core/+/android-7.1.1_r13/libutils/String8.cpp
+// and https://android.googlesource.com/platform/system/core/+/android-7.1.1_r13/include/utils/String8.h
+public class String8 {
+
+  private StringBuilder mString;
+
+  public String8() {
+    this("");
+  }
+
+  public String8(String value) {
+    mString = new StringBuilder(value);
+  }
+
+  public String8(String8 path) {
+    this(path.string());
+  }
+
+//size_t String8::length() const
+//{
+//    return SharedBuffer::sizeFromData(mString)-1;
+//}
+//String8 String8::format(const char* fmt, ...)
+//{
+//    va_list args;
+//    va_start(args, fmt);
+//    String8 result(formatV(fmt, args));
+//    va_end(args);
+//    return result;
+//}
+//String8 String8::formatV(const char* fmt, va_list args)
+//{
+//    String8 result;
+//    result.appendFormatV(fmt, args);
+//    return result;
+//}
+//void String8::clear() {
+//    SharedBuffer::bufferFromData(mString)->release();
+//    mString = getEmptyString();
+//}
+//void String8::setTo(const String8& other)
+//{
+//    SharedBuffer::bufferFromData(other.mString)->acquire();
+//    SharedBuffer::bufferFromData(mString)->release();
+//    mString = other.mString;
+//}
+//status_t String8::setTo(const char* other)
+//{
+//    const char *newString = allocFromUTF8(other, strlen(other));
+//    SharedBuffer::bufferFromData(mString)->release();
+//    mString = newString;
+//    if (mString) return NO_ERROR;
+//    mString = getEmptyString();
+//    return NO_MEMORY;
+//}
+//status_t String8::setTo(const char* other, size_t len)
+//{
+//    const char *newString = allocFromUTF8(other, len);
+//    SharedBuffer::bufferFromData(mString)->release();
+//    mString = newString;
+//    if (mString) return NO_ERROR;
+//    mString = getEmptyString();
+//    return NO_MEMORY;
+//}
+//status_t String8::setTo(const char16_t* other, size_t len)
+//{
+//    const char *newString = allocFromUTF16(other, len);
+//    SharedBuffer::bufferFromData(mString)->release();
+//    mString = newString;
+//    if (mString) return NO_ERROR;
+//    mString = getEmptyString();
+//    return NO_MEMORY;
+//}
+//status_t String8::setTo(const char32_t* other, size_t len)
+//{
+//    const char *newString = allocFromUTF32(other, len);
+//    SharedBuffer::bufferFromData(mString)->release();
+//    mString = newString;
+//    if (mString) return NO_ERROR;
+//    mString = getEmptyString();
+//    return NO_MEMORY;
+//}
+//status_t String8::append(const String8& other)
+//{
+//    const size_t otherLen = other.bytes();
+//    if (bytes() == 0) {
+//        setTo(other);
+//        return NO_ERROR;
+//    } else if (otherLen == 0) {
+//        return NO_ERROR;
+//    }
+//    return real_append(other.string(), otherLen);
+//}
+public String8 append(final String other) {
+  mString.append(other);
+    return this;
+}
+//status_t String8::append(const char* other, size_t otherLen)
+//{
+//    if (bytes() == 0) {
+//        return setTo(other, otherLen);
+//    } else if (otherLen == 0) {
+//        return NO_ERROR;
+//    }
+//    return real_append(other, otherLen);
+//}
+//status_t String8::appendFormat(const char* fmt, ...)
+//{
+//    va_list args;
+//    va_start(args, fmt);
+//    status_t result = appendFormatV(fmt, args);
+//    va_end(args);
+//    return result;
+//}
+//status_t String8::appendFormatV(const char* fmt, va_list args)
+//{
+//    int n, result = NO_ERROR;
+//    va_list tmp_args;
+//    /* args is undefined after vsnprintf.
+//     * So we need a copy here to avoid the
+//     * second vsnprintf access undefined args.
+//     */
+//    va_copy(tmp_args, args);
+//    n = vsnprintf(NULL, 0, fmt, tmp_args);
+//    va_end(tmp_args);
+//    if (n != 0) {
+//        size_t oldLength = length();
+//        char* buf = lockBuffer(oldLength + n);
+//        if (buf) {
+//            vsnprintf(buf + oldLength, n + 1, fmt, args);
+//        } else {
+//            result = NO_MEMORY;
+//        }
+//    }
+//    return result;
+//}
+//status_t String8::real_append(const char* other, size_t otherLen)
+//{
+//    const size_t myLen = bytes();
+//
+//    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+//        ->editResize(myLen+otherLen+1);
+//    if (buf) {
+//        char* str = (char*)buf->data();
+//        mString = str;
+//        str += myLen;
+//        memcpy(str, other, otherLen);
+//        str[otherLen] = '\0';
+//        return NO_ERROR;
+//    }
+//    return NO_MEMORY;
+//}
+//char* String8::lockBuffer(size_t size)
+//{
+//    SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+//        ->editResize(size+1);
+//    if (buf) {
+//        char* str = (char*)buf->data();
+//        mString = str;
+//        return str;
+//    }
+//    return NULL;
+//}
+//void String8::unlockBuffer()
+//{
+//    unlockBuffer(strlen(mString));
+//}
+//status_t String8::unlockBuffer(size_t size)
+//{
+//    if (size != this->size()) {
+//        SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
+//            ->editResize(size+1);
+//        if (! buf) {
+//            return NO_MEMORY;
+//        }
+//        char* str = (char*)buf->data();
+//        str[size] = 0;
+//        mString = str;
+//    }
+//    return NO_ERROR;
+//}
+//ssize_t String8::find(const char* other, size_t start) const
+//{
+//    size_t len = size();
+//    if (start >= len) {
+//        return -1;
+//    }
+//    const char* s = mString+start;
+//    const char* p = strstr(s, other);
+//    return p ? p-mString : -1;
+//}
+//bool String8::removeAll(const char* other) {
+//    ssize_t index = find(other);
+//    if (index < 0) return false;
+//    char* buf = lockBuffer(size());
+//    if (!buf) return false; // out of memory
+//    size_t skip = strlen(other);
+//    size_t len = size();
+//    size_t tail = index;
+//    while (size_t(index) < len) {
+//        ssize_t next = find(other, index + skip);
+//        if (next < 0) {
+//            next = len;
+//        }
+//        memmove(buf + tail, buf + index + skip, next - index - skip);
+//        tail += next - index - skip;
+//        index = next;
+//    }
+//    unlockBuffer(tail);
+//    return true;
+//}
+//void String8::toLower()
+//{
+//    toLower(0, size());
+//}
+//void String8::toLower(size_t start, size_t length)
+//{
+//    const size_t len = size();
+//    if (start >= len) {
+//        return;
+//    }
+//    if (start+length > len) {
+//        length = len-start;
+//    }
+//    char* buf = lockBuffer(len);
+//    buf += start;
+//    while (length > 0) {
+//        *buf = tolower(*buf);
+//        buf++;
+//        length--;
+//    }
+//    unlockBuffer(len);
+//}
+//void String8::toUpper()
+//{
+//    toUpper(0, size());
+//}
+//void String8::toUpper(size_t start, size_t length)
+//{
+//    const size_t len = size();
+//    if (start >= len) {
+//        return;
+//    }
+//    if (start+length > len) {
+//        length = len-start;
+//    }
+//    char* buf = lockBuffer(len);
+//    buf += start;
+//    while (length > 0) {
+//        *buf = toupper(*buf);
+//        buf++;
+//        length--;
+//    }
+//    unlockBuffer(len);
+//}
+//size_t String8::getUtf32Length() const
+//{
+//    return utf8_to_utf32_length(mString, length());
+//}
+//int32_t String8::getUtf32At(size_t index, size_t *next_index) const
+//{
+//    return utf32_from_utf8_at(mString, length(), index, next_index);
+//}
+//void String8::getUtf32(char32_t* dst) const
+//{
+//    utf8_to_utf32(mString, length(), dst);
+//}
+//// ---------------------------------------------------------------------------
+//// Path functions
+//void String8::setPathName(const char* name)
+//{
+//    setPathName(name, strlen(name));
+//}
+//void String8::setPathName(const char* name, size_t len)
+//{
+//    char* buf = lockBuffer(len);
+//    memcpy(buf, name, len);
+//    // remove trailing path separator, if present
+//    if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
+//        len--;
+//    buf[len] = '\0';
+//    unlockBuffer(len);
+//}
+//String8 String8::getPathLeaf(void) const
+//{
+//    const char* cp;
+//    const char*const buf = mString;
+//    cp = strrchr(buf, OS_PATH_SEPARATOR);
+//    if (cp == NULL)
+//        return String8(*this);
+//    else
+//        return String8(cp+1);
+//}
+//String8 String8::getPathDir(void) const
+//{
+//    const char* cp;
+//    const char*const str = mString;
+//    cp = strrchr(str, OS_PATH_SEPARATOR);
+//    if (cp == NULL)
+//        return String8("");
+//    else
+//        return String8(str, cp - str);
+//}
+//String8 String8::walkPath(String8* outRemains) const
+//{
+//    const char* cp;
+//    const char*const str = mString;
+//    const char* buf = str;
+//    cp = strchr(buf, OS_PATH_SEPARATOR);
+//    if (cp == buf) {
+//        // don't include a leading '/'.
+//        buf = buf+1;
+//        cp = strchr(buf, OS_PATH_SEPARATOR);
+//    }
+//    if (cp == NULL) {
+//        String8 res = buf != str ? String8(buf) : *this;
+//        if (outRemains) *outRemains = String8("");
+//        return res;
+//    }
+//    String8 res(buf, cp-buf);
+//    if (outRemains) *outRemains = String8(cp+1);
+//    return res;
+//}
+
+/*
+ * Helper function for finding the start of an extension in a pathname.
+ *
+ * Returns a index inside mString, or -1 if no extension was found.
+ */
+private int find_extension()
+{
+    int lastSlashIndex;
+
+    final StringBuilder str = mString;
+    // only look at the filename
+    lastSlashIndex = str.lastIndexOf(File.pathSeparator);
+    if (lastSlashIndex == -1) {
+      lastSlashIndex = 0;
+    } else {
+      lastSlashIndex++;
+    }
+    // find the last dot
+    return str.lastIndexOf(".", lastSlashIndex);
+}
+
+public String getPathExtension()
+{
+    int extIndex;
+    extIndex = find_extension();
+    if (extIndex != -1) {
+      return mString.substring(extIndex);
+    }
+    else {
+      return "";
+    }
+}
+//String8 String8::getBasePath(void) const
+//{
+//    char* ext;
+//    const char* const str = mString;
+//    ext = find_extension();
+//    if (ext == NULL)
+//        return String8(*this);
+//    else
+//        return String8(str, ext - str);
+//}
+
+  public String8 appendPath(String name) {
+    if (name.length() == 0) {
+      // nothing to do
+      return this;
+    }
+    if (name.charAt(0) != File.pathSeparatorChar) {
+      mString.append(File.pathSeparatorChar);
+    }
+    mString.append(name);
+    return this;
+}
+
+//String8& String8::convertToResPath()
+//{
+//#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
+//    size_t len = length();
+//    if (len > 0) {
+//        char * buf = lockBuffer(len);
+//        for (char * end = buf + len; buf < end; ++buf) {
+//            if (*buf == OS_PATH_SEPARATOR)
+//                *buf = RES_PATH_SEPARATOR;
+//        }
+//        unlockBuffer(len);
+//    }
+//#endif
+//    return *this;
+//}
+//}; // namespace android
+
+  public final String string() {
+    return mString.toString();
+  }
+}
+
+
diff --git a/resources/src/main/java/org/robolectric/res/android/Util.java b/resources/src/main/java/org/robolectric/res/android/Util.java
index f54ab83..8e186e7 100644
--- a/resources/src/main/java/org/robolectric/res/android/Util.java
+++ b/resources/src/main/java/org/robolectric/res/android/Util.java
@@ -44,8 +44,8 @@
     System.out.println(String.format(message, args));
   }
 
-  static void ALOGV(String message, int level) {
-    System.out.println(message);
+  static void ALOGV(String message, Object... args) {
+    System.out.println(String.format(message, args));
   }
 
   static void ALOGI(String message, Object... args) {
@@ -53,10 +53,7 @@
   }
 
   static void LOG_FATAL_IF(boolean assertion, String message) {
-    if (!assertion) {
-      System.out.println(message);
-    }
-    assert assertion;
+    assert !assertion : message;
   }
 
   static void ATRACE_CALL() {
diff --git a/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java b/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java
index d6b4a74..658c063 100644
--- a/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java
+++ b/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java
@@ -29,7 +29,7 @@
 /** Provides utilities to decode/encode a String packed in an arsc resource file. */
 public final class ResourceString {
 
-  /** Type of {@link ResourceString} to encode / decode. */
+  /** DataType of {@link ResourceString} to encode / decode. */
   public enum Type {
     UTF8(UTF_8),
     UTF16(UTF_16LE);
diff --git a/resources/src/test/java/org/robolectric/res/android/ResTableTest.java b/resources/src/test/java/org/robolectric/res/android/ResTableTest.java
index ba8ba73..de4d8e2 100644
--- a/resources/src/test/java/org/robolectric/res/android/ResTableTest.java
+++ b/resources/src/test/java/org/robolectric/res/android/ResTableTest.java
@@ -35,25 +35,26 @@
   @Test
   public void testGetEntry_intType() {
     Entry entry = resTable.getEntry(R.integer.flock_size, null);
-    assertThat(entry.entry.value.dataType).isEqualTo(Type.INT_DEC.code());
+    assertThat(entry.entry.value.dataType).isEqualTo(DataType.INT_DEC.code());
     assertThat(entry.entry.value.data).isEqualTo(1234);
   }
 
   @Test
   public void testGetEntry_intType_large() {
     Entry entry = resTable.getEntry(R.integer.flock_size, "large");
-    assertThat(entry.entry.value.dataType).isEqualTo(Type.INT_DEC.code());
+    assertThat(entry.entry.value.dataType).isEqualTo(DataType.INT_DEC.code());
     assertThat(entry.entry.value.data).isEqualTo(1000000);
   }
 
   @Test
   public void testGetEntry_stringType() throws Exception {
-    assertThat(resTable.getEntry(R.string.first_string, null).entry.value.dataType).isEqualTo(Type.STRING.code());
+    assertThat(resTable.getEntry(R.string.first_string, null).entry.value.dataType).isEqualTo(
+        DataType.STRING.code());
   }
 
   @Test
   public void testGetEntry_boolType() throws Exception {
-    assertThat(resTable.getEntry(R.bool.is_verizon, null).entry.value.dataType).isEqualTo(Type.INT_BOOLEAN.code());
+    assertThat(resTable.getEntry(R.bool.is_verizon, null).entry.value.dataType).isEqualTo(DataType.INT_BOOLEAN.code());
     // Uncomment when we start selecting correct configuration
 //    assertThat(resTable.getEntry(R.bool.is_verizon, 0).value.dataType).isEqualTo(0);
   }
diff --git a/robolectric/build.gradle b/robolectric/build.gradle
index c4e0ac4..5370af5 100644
--- a/robolectric/build.gradle
+++ b/robolectric/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/sandbox/build.gradle b/sandbox/build.gradle
index da008de..371b11d 100644
--- a/sandbox/build.gradle
+++ b/sandbox/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/shadowapi/build.gradle b/shadowapi/build.gradle
index f10e1d3..ebd519b 100644
--- a/shadowapi/build.gradle
+++ b/shadowapi/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/shadows/framework/build.gradle b/shadows/framework/build.gradle
index c0da4f4..004b8fb 100644
--- a/shadows/framework/build.gradle
+++ b/shadows/framework/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java b/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java
index 967f158..b11067d 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java
@@ -37,7 +37,7 @@
       case "fraction":
         return new FromFraction();
       default:
-        throw new UnsupportedOperationException("Type not supported: " + type);
+        throw new UnsupportedOperationException("DataType not supported: " + type);
     }
   }
 
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java
index 9021611..be232b7 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java
@@ -47,7 +47,7 @@
     } else {
       invokeConstructor(AssetManager.class, realObject);
       resTable = loadAppResTable();
-      cppAssetManager = new CppAssetManager(this);
+      cppAssetManager = new CppAssetManager();
     }
   }
 
@@ -61,7 +61,7 @@
       invokeConstructor(AssetManager.class, realObject,
           ClassParameter.from(boolean.class, isSystem));
       resTable = isSystem ? loadSystemResTable() : loadAppResTable();
-      cppAssetManager = new CppAssetManager(this);
+      cppAssetManager = new CppAssetManager();
     }
   }
 
@@ -429,7 +429,7 @@
   public int loadResourceValue(int ident, short density, TypedValue outValue, boolean resolve) {
     if (outValue == null) {
       throw new NullPointerException("outValue");
-      return 0;
+      //return 0;
     }
     CppAssetManager am = assetManagerForJavaObject();
     if (am == null) {
@@ -444,25 +444,43 @@
     if (kThrowOnBadId) {
         if (block == BAD_INDEX) {
             throw new IllegalStateException("Bad resource!");
-            return 0;
+            //return 0;
         }
     }
     Ref<Integer> ref = new Ref<>(ident);
     if (resolve) {
-        block = res.resolveReference(value, block, ref, typeSpecFlags, config);
+        block = res.resolveReference(value.get(), block, ref, typeSpecFlags, config);
         if (kThrowOnBadId) {
             if (block == BAD_INDEX) {
               throw new IllegalStateException("Bad resource!");
-                return 0;
+                //return 0;
             }
         }
     }
     if (block >= 0) {
-        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+        //return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+      return copyValue(outValue, res, value.get(), ref.get(), block, typeSpecFlags.get(),
+          config.get());
+
     }
-    return static_cast<jint>(block);
+    return block;
 }
 
+  int copyValue(TypedValue outValue, ResTable table,  ResValue value, int ref, int block,
+      int typeSpecFlags, ResTableConfig config) {
+    outValue.type = value.dataType;
+    outValue.assetCookie = table.getTableCookie(block);
+    outValue.data = value.data;
+    outValue.string = null;
+    outValue.resourceId = ref;
+    outValue.changingConfigurations = typeSpecFlags;
+
+    if (config != null) {
+      outValue.density = config.density;
+    }
+    return block;
+  }
+
 //  /** Returns true if the resource was found, filling in mRetStringBlock and
 //   *  mRetData. */
 //  private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
index 6311386..244d3c8 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
@@ -63,7 +63,7 @@
     for (int index = 0; index < data.length; index+= ShadowAssetManager.STYLE_NUM_ENTRIES) {
       final int type = data[index+ShadowAssetManager.STYLE_TYPE];
       result.append("Index: ").append(index / ShadowAssetManager.STYLE_NUM_ENTRIES).append(System.lineSeparator());
-      result.append(Strings.padEnd("Type: ", 25, ' ')).append(TYPE_MAP.get(type)).append(System.lineSeparator());
+      result.append(Strings.padEnd("DataType: ", 25, ' ')).append(TYPE_MAP.get(type)).append(System.lineSeparator());
       if (type != TypedValue.TYPE_NULL) {
         result.append(Strings.padEnd("Style data: ", 25, ' ')).append(data[index+ ShadowAssetManager.STYLE_DATA]).append(System.lineSeparator());
         result.append(Strings.padEnd("Asset cookie ", 25, ' ')).append(data[index+ShadowAssetManager.STYLE_ASSET_COOKIE]).append(System.lineSeparator());
diff --git a/shadows/httpclient/build.gradle b/shadows/httpclient/build.gradle
index cf1492a..97396d4 100644
--- a/shadows/httpclient/build.gradle
+++ b/shadows/httpclient/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java b/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java
index 8cc8fa9..6e5320c 100644
--- a/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java
+++ b/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java
@@ -193,7 +193,7 @@
     }
 
     @Override public Header getContentType() {
-      return getFirstHeader("Content-Type");
+      return getFirstHeader("Content-DataType");
     }
 
     @Override public Header getContentEncoding() {
diff --git a/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java b/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java
index 59fd721..ccca270 100644
--- a/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java
+++ b/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java
@@ -288,7 +288,7 @@
 
   @Test
   public void shouldSupportBasicResponseHandlerHandleResponse() throws Exception {
-    FakeHttp.addPendingHttpResponse(200, "OK", new BasicHeader("Content-Type", "text/plain"));
+    FakeHttp.addPendingHttpResponse(200, "OK", new BasicHeader("Content-DataType", "text/plain"));
 
     DefaultHttpClient client = new DefaultHttpClient();
     HttpResponse response = client.execute(new HttpGet("http://www.nowhere.org"));
diff --git a/shadows/maps/build.gradle b/shadows/maps/build.gradle
index 864a947..0b168f2 100644
--- a/shadows/maps/build.gradle
+++ b/shadows/maps/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/shadows/multidex/build.gradle b/shadows/multidex/build.gradle
index 57e2757..b29dace 100644
--- a/shadows/multidex/build.gradle
+++ b/shadows/multidex/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/shadows/playservices/build.gradle b/shadows/playservices/build.gradle
index 26863f0..14e9905 100644
--- a/shadows/playservices/build.gradle
+++ b/shadows/playservices/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/shadows/supportv4/build.gradle b/shadows/supportv4/build.gradle
index e131eb2..7d0f13f 100644
--- a/shadows/supportv4/build.gradle
+++ b/shadows/supportv4/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(
diff --git a/utils/build.gradle b/utils/build.gradle
index 80c5894..2257849 100644
--- a/utils/build.gradle
+++ b/utils/build.gradle
@@ -1,5 +1,5 @@
 plugins {
-    id "net.ltgt.errorprone" version "0.0.10"
+    //id "net.ltgt.errorprone" version "0.0.11"
 }
 
 new RoboJavaModulePlugin(