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

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

package org.robolectric.shadows;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.NinePatch;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.Resetter;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.internal.Shadow;
import org.robolectric.util.ReflectionHelpers.ClassParameter;

import static org.robolectric.Shadows.shadowOf;

/**
 * Shadow for {@link android.graphics.drawable.Drawable}.
 */
@SuppressWarnings({"UnusedDeclaration"})
@Implements(Drawable.class)
public class ShadowDrawable {
  private static int defaultIntrinsicWidth = -1;
  private static int defaultIntrinsicHeight = -1;
  static final List corruptStreamSources = new ArrayList<>();

  @RealObject Drawable realDrawable;

  int createdFromResId = -1;
  InputStream createdFromInputStream;

  private int intrinsicWidth = defaultIntrinsicWidth;
  private int intrinsicHeight = defaultIntrinsicHeight;
  private int alpha;
  private boolean wasInvalidated;

  @Implementation
  public static Drawable createFromStream(InputStream is, String srcName) {
    if (corruptStreamSources.contains(srcName)) {
      return null;
    }
    BitmapDrawable drawable = new BitmapDrawable(ReflectionHelpers.callConstructor(Bitmap.class));
    shadowOf(drawable).createdFromInputStream = is;
    shadowOf(drawable).drawableCreateFromStreamSource = srcName;
    shadowOf(drawable).validate(); // start off not invalidated
    return drawable;
  }

  @Implementation // todo: this sucks, it's all just so we can detect 9-patches
  public static Drawable createFromResourceStream(Resources res, TypedValue value,
                          InputStream is, String srcName, BitmapFactory.Options opts) {
    if (is == null) {
      return null;
    }
    Rect pad = new Rect();
    if (opts == null) opts = new BitmapFactory.Options();
    opts.inScreenDensity = DisplayMetrics.DENSITY_DEFAULT;

    Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
    if (bm != null) {
      boolean isNinePatch = srcName != null && srcName.contains(".9.");
      if (isNinePatch) {
        ReflectionHelpers.callInstanceMethod(bm, "setNinePatchChunk", ClassParameter.from(byte[].class, new byte[0]));
      }
      byte[] np = bm.getNinePatchChunk();
      if (np == null || !NinePatch.isNinePatchChunk(np)) {
        np = null;
        pad = null;
      }

      if (np != null) {
        // todo: wrong
        return new NinePatchDrawable(res, bm, np, pad, srcName);
      }

      return new BitmapDrawable(res, bm);
    }
    return null;
  }

  @Implementation
  public static Drawable createFromPath(String pathName) {
    BitmapDrawable drawable = new BitmapDrawable(ReflectionHelpers.callConstructor(Bitmap.class));
    shadowOf(drawable).drawableCreateFromPath = pathName;
    shadowOf(drawable).validate(); // start off not invalidated
    return drawable;
  }

  public static Drawable createFromResourceId(int resourceId) {
    Bitmap bitmap = ReflectionHelpers.callConstructor(Bitmap.class);
    shadowOf(bitmap).createdFromResId = resourceId;
    BitmapDrawable drawable = new BitmapDrawable(bitmap);
    shadowOf(drawable).validate(); // start off not invalidated
    shadowOf(drawable).createdFromResId = resourceId;
    return drawable;
  }

  @Implementation
  public int getIntrinsicWidth() {
    return intrinsicWidth;
  }

  @Implementation
  public int getIntrinsicHeight() {
    return intrinsicHeight;
  }

  public static void addCorruptStreamSource(String src) {
    corruptStreamSources.add(src);
  }

  @Resetter
  public static void clearCorruptStreamSources() {
    corruptStreamSources.clear();
  }

  public static void setDefaultIntrinsicWidth(int defaultIntrinsicWidth) {
    ShadowDrawable.defaultIntrinsicWidth = defaultIntrinsicWidth;
  }

  public static void setDefaultIntrinsicHeight(int defaultIntrinsicHeight) {
    ShadowDrawable.defaultIntrinsicHeight = defaultIntrinsicHeight;
  }

  public void setIntrinsicWidth(int intrinsicWidth) {
    this.intrinsicWidth = intrinsicWidth;
  }

  public void setIntrinsicHeight(int intrinsicHeight) {
    this.intrinsicHeight = intrinsicHeight;
  }

  public InputStream getInputStream() {
    return createdFromInputStream;
  }

  @Override @Implementation
  public boolean equals(Object o) {
    if (realDrawable == o) return true;
    if (o == null || realDrawable.getClass() != o.getClass()) return false;

    ShadowDrawable that = shadowOf((Drawable) o);

    if (intrinsicHeight != that.intrinsicHeight) return false;
    if (intrinsicWidth != that.intrinsicWidth) return false;
    Rect bounds = realDrawable.getBounds();
    Rect thatBounds = that.realDrawable.getBounds();
    if (bounds != null ? !bounds.equals(thatBounds) : thatBounds != null) return false;

    return true;
  }

  @Override @Implementation
  public int hashCode() {
    Rect bounds = realDrawable.getBounds();
    int result = bounds != null ? bounds.hashCode() : 0;
    result = 31 * result + intrinsicWidth;
    result = 31 * result + intrinsicHeight;
    return result;
  }

  @Implementation
  public void setAlpha(int alpha) {
    this.alpha = alpha;
    Shadow.directlyOn(realDrawable, Drawable.class).setAlpha(alpha);
  }

  @Implementation
  public void invalidateSelf() {
    wasInvalidated = true;
    Shadow.directlyOn(realDrawable, Drawable.class, "invalidateSelf");
  }

  @Implementation
  public int getAlpha() {
    return alpha;
  }

  /** @deprecated Use {@link #clearCorruptStreamSources()}. */
  @Deprecated
  public static void reset() {
    clearCorruptStreamSources();
  }

  public int getCreatedFromResId() {
    return createdFromResId;
  }

  public boolean wasInvalidated() {
    return wasInvalidated;
  }

  public void validate() {
    wasInvalidated = false;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy