All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robolectric.shadows.ShadowNativeImageDecoder Maven / Gradle / Ivy

The newest version!
package org.robolectric.shadows;

import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.R;
import static android.os.Build.VERSION_CODES.S;
import static org.robolectric.util.reflector.Reflector.reflector;

import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager.AssetInputStream;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.ImageDecoder;
import android.graphics.ImageDecoder.Source;
import android.graphics.Rect;
import android.util.Size;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.nativeruntime.DefaultNativeRuntimeLoader;
import org.robolectric.nativeruntime.ImageDecoderNatives;
import org.robolectric.shadows.ShadowNativeImageDecoder.Picker;
import org.robolectric.util.reflector.ForType;
import org.robolectric.util.reflector.Static;
import org.robolectric.versioning.AndroidVersions.U;

/** Shadow for {@link android.graphics.ImageDecoder} that is backed by native code */
@Implements(
    value = ImageDecoder.class,
    minSdk = P,
    shadowPicker = Picker.class,
    callNativeMethodsByDefault = true)
public class ShadowNativeImageDecoder {

  static {
    DefaultNativeRuntimeLoader.injectAndLoad();
  }

  @Implementation(minSdk = P, maxSdk = Q)
  protected static ImageDecoder createFromAsset(AssetInputStream ais, Source source)
      throws IOException {
    return createFromAsset(ais, false, source);
  }

  @Implementation(minSdk = R)
  protected static ImageDecoder createFromAsset(
      AssetInputStream ais, boolean preferAnimation, Source source) throws IOException {
    int capacity = ais.available();
    ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
    buffer.order(ByteOrder.nativeOrder());
    byte[] buf = new byte[8 * 1024]; // 8k
    int bytesRead;
    while ((bytesRead = ais.read(buf)) != -1) {
      buffer.put(buf, 0, bytesRead);
    }
    if (ais.read() != -1) {
      throw new IOException("Unable to access full contents of asset");
    }
    if (RuntimeEnvironment.getApiLevel() > U.SDK_INT) {
      return reflector(ImageDecoderReflector.class)
          .nCreate(buffer, 0, bytesRead, preferAnimation, source);
    } else {
      return nCreate(buffer, 0, bytesRead, preferAnimation, source);
    }
  }

  @Implementation(minSdk = P, maxSdk = Q)
  protected static ImageDecoder nCreate(long asset, Source src) throws IOException {
    return nCreate(asset, false, src);
  }

  @Implementation(minSdk = R)
  protected static ImageDecoder nCreate(long asset, boolean preferAnimation, Source src)
      throws IOException {
    throw new UnsupportedEncodingException();
  }

  @Implementation(minSdk = P, maxSdk = Q)
  protected static ImageDecoder nCreate(ByteBuffer buffer, int position, int limit, Source src)
      throws IOException {
    return nCreate(buffer, position, limit, false, src);
  }

  @Implementation(minSdk = R, maxSdk = U.SDK_INT)
  protected static ImageDecoder nCreate(
      ByteBuffer buffer, int position, int limit, boolean preferAnimation, Source src)
      throws IOException {
    return ImageDecoderNatives.nCreate(buffer, position, limit, preferAnimation, src);
  }

  @Implementation(minSdk = P, maxSdk = Q)
  protected static ImageDecoder nCreate(byte[] data, int offset, int length, Source src)
      throws IOException {
    return nCreate(data, offset, length, false, src);
  }

  @Implementation(minSdk = R, maxSdk = U.SDK_INT)
  protected static ImageDecoder nCreate(
      byte[] data, int offset, int length, boolean preferAnimation, Source src) throws IOException {
    return ImageDecoderNatives.nCreate(data, offset, length, preferAnimation, src);
  }

  @Implementation(minSdk = P, maxSdk = Q)
  protected static ImageDecoder nCreate(InputStream is, byte[] storage, Source src)
      throws IOException {
    return nCreate(is, storage, false, src);
  }

  @Implementation(minSdk = R, maxSdk = U.SDK_INT)
  protected static ImageDecoder nCreate(
      InputStream is, byte[] storage, boolean preferAnimation, Source src) throws IOException {
    return ImageDecoderNatives.nCreate(is, storage, preferAnimation, src);
  }

  @Implementation(maxSdk = Q)
  protected static ImageDecoder nCreate(FileDescriptor fd, Source src) throws IOException {
    return nCreate(fd, AssetFileDescriptor.UNKNOWN_LENGTH, false, src);
  }

  @Implementation(minSdk = R, maxSdk = R)
  protected static ImageDecoder nCreate(FileDescriptor fd, boolean preferAnimation, Source src)
      throws IOException {
    return nCreate(fd, AssetFileDescriptor.UNKNOWN_LENGTH, preferAnimation, src);
  }

  @Implementation(minSdk = S, maxSdk = U.SDK_INT)
  protected static ImageDecoder nCreate(
      FileDescriptor fd, long length, boolean preferAnimation, Source src) throws IOException {
    return ImageDecoderNatives.nCreate(fd, length, preferAnimation, src);
  }

  @Implementation(minSdk = P, maxSdk = P)
  protected static Bitmap nDecodeBitmap(
      long nativePtr,
      ImageDecoder decoder,
      boolean doPostProcess,
      int width,
      int height,
      Rect cropRect,
      boolean mutable,
      int allocator,
      boolean unpremulRequired,
      boolean conserveMemory,
      boolean decodeAsAlphaMask,
      ColorSpace desiredColorSpace)
      throws IOException {
    return nDecodeBitmap(
        nativePtr,
        decoder,
        doPostProcess,
        width,
        height,
        cropRect,
        mutable,
        allocator,
        unpremulRequired,
        conserveMemory,
        decodeAsAlphaMask,
        /* desiredColorSpace= */ 0, // Desired color space is currently not supported in P.
        /* extended= */ false);
  }

  @Implementation(minSdk = Q, maxSdk = U.SDK_INT)
  protected static Bitmap nDecodeBitmap(
      long nativePtr,
      ImageDecoder decoder,
      boolean doPostProcess,
      int width,
      int height,
      Rect cropRect,
      boolean mutable,
      int allocator,
      boolean unpremulRequired,
      boolean conserveMemory,
      boolean decodeAsAlphaMask,
      long desiredColorSpace,
      boolean extended)
      throws IOException {
    return ImageDecoderNatives.nDecodeBitmap(
        nativePtr,
        decoder,
        doPostProcess,
        width,
        height,
        cropRect,
        mutable,
        allocator,
        unpremulRequired,
        conserveMemory,
        decodeAsAlphaMask,
        desiredColorSpace,
        extended);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected static Size nGetSampledSize(long nativePtr, int sampleSize) {
    return ImageDecoderNatives.nGetSampledSize(nativePtr, sampleSize);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected static void nGetPadding(long nativePtr, Rect outRect) {
    ImageDecoderNatives.nGetPadding(nativePtr, outRect);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected static void nClose(long nativePtr) {
    ImageDecoderNatives.nClose(nativePtr);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected static String nGetMimeType(long nativePtr) {
    return ImageDecoderNatives.nGetMimeType(nativePtr);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected static ColorSpace nGetColorSpace(long nativePtr) {
    return ImageDecoderNatives.nGetColorSpace(nativePtr);
  }

  @ForType(ImageDecoder.class)
  interface ImageDecoderReflector {
    @Static
    ImageDecoder nCreate(
        ByteBuffer buffer, int position, int limit, boolean preferAnimation, Source src);
  }

  /** Shadow picker for {@link ImageDecoder}. */
  public static final class Picker extends GraphicsShadowPicker {
    public Picker() {
      super(ShadowImageDecoder.class, ShadowNativeImageDecoder.class);
    }
  }
}