BitmapFactory.decodeStream from Assets returns null on Android 7

I think we are in the same boat. My team stuck in this problem for a while like you.

It seems be a problem in BitmapFactory.cpp (https://android.googlesource.com/platform/frameworks/base.git/+/master/core/jni/android/graphics/BitmapFactory.cpp) Some code was added in Android 7.0 and made the problem occurred.

// Create the codec.
NinePatchPeeker peeker;
std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), &peeker));
if (!codec.get()) {
    return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
}

And I found out the BitmapFactory.decodeStream method didn't create the bitmap after we set inJustDecodeBounds=false but when I try to create bitmap without bound decoding. It's works! The problem is about BitmapOptions in that InputStream doesn't updated when we called BitmapFactory.decodeStream again.

So I reset that InputStream before decode again

private Bitmap getBitmapFromAssets(Context context, String fileName, int width, int height) {
    AssetManager asset = context.getAssets();
    InputStream is;
    try {
        is = asset.open(fileName);
    } catch (IOException e) {
        return null;
    }
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(is, null, options);
    try {
        is.reset();
    } catch (IOException e) {
        return null;
    }
    options.inSampleSize = calculateInSampleSize(options, width, height);
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeStream(is, null, options);
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

It's looks like we have to reset InputStream every time before reuse it.