aboutsummaryrefslogtreecommitdiff
path: root/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeImageReader.java
blob: 633f1062cf00f431ff3b561f1301e0218f063e79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package org.robolectric.shadows;

import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.S;
import static android.os.Build.VERSION_CODES.S_V2;

import android.media.Image;
import android.media.ImageReader;
import android.view.Surface;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.ReflectorObject;
import org.robolectric.nativeruntime.DefaultNativeRuntimeLoader;
import org.robolectric.nativeruntime.ImageReaderNatives;
import org.robolectric.shadows.ShadowNativeImageReader.Picker;
import org.robolectric.util.reflector.Accessor;
import org.robolectric.util.reflector.ForType;
import org.robolectric.versioning.AndroidVersions.T;
import org.robolectric.versioning.AndroidVersions.U;
import org.robolectric.versioning.AndroidVersions.V;

/** Shadow for {@link ImageReader} that is backed by native code */
@Implements(
    value = ImageReader.class,
    minSdk = Q,
    looseSignatures = true,
    isInAndroidSdk = false,
    shadowPicker = Picker.class,
    callNativeMethodsByDefault = true)
public class ShadowNativeImageReader {

  /**
   * The {@link ImageReader} static initializer invokes its own native methods in static
   * initializer. This has to be deferred starting in Android V.
   */
  @Implementation(minSdk = V.SDK_INT)
  protected static void __staticInitializer__() {
    // deferred
  }

  @ReflectorObject private ImageReaderReflector imageReaderReflector;
  private final ImageReaderNatives natives = new ImageReaderNatives();

  @Implementation(maxSdk = S_V2)
  protected synchronized void nativeInit(
      Object weakSelf, int w, int h, int fmt, int maxImgs, long consumerUsage) {
    natives.nativeInit(weakSelf, w, h, fmt, maxImgs, consumerUsage);
    imageReaderReflector.setMemberNativeContext(natives.mNativeContext);
  }

  @Implementation(minSdk = T.SDK_INT, maxSdk = U.SDK_INT)
  protected synchronized void nativeInit(
      Object weakSelf,
      int w,
      int h,
      int maxImgs,
      long consumerUsage,
      int hardwareBufferFormat,
      int dataSpace) {
    // Up to S, "fmt" is a PublicFormat (JNI), aka ImageFormat.format (java), which is then
    // split into a hal format + data space in the JNI code.
    // In T+, the hal format and data space are provided directly instead.
    // However the format values overlap and the conversion is merely a cast.
    // Reference: android12/.../frameworks/base/libs/hostgraphics/PublicFormat.cpp
    int fmt = hardwareBufferFormat;
    natives.nativeInit(weakSelf, w, h, fmt, maxImgs, consumerUsage);
    imageReaderReflector.setMemberNativeContext(natives.mNativeContext);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected void nativeClose() {
    natives.nativeClose();
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected void nativeReleaseImage(Image i) {
    natives.nativeReleaseImage(i);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected Surface nativeGetSurface() {
    return natives.nativeGetSurface();
  }

  @Implementation(maxSdk = S_V2)
  protected int nativeDetachImage(Image i) {
    return natives.nativeDetachImage(i);
  }

  @Implementation(maxSdk = U.SDK_INT)
  protected void nativeDiscardFreeBuffers() {
    natives.nativeDiscardFreeBuffers();
  }

  /**
   * @return A return code {@code ACQUIRE_*}
   */
  @Implementation(maxSdk = S_V2)
  protected int nativeImageSetup(Image i) {
    return natives.nativeImageSetup(i);
  }

  @Implementation(minSdk = T.SDK_INT, maxSdk = T.SDK_INT)
  protected int nativeImageSetup(Image i, boolean legacyValidateImageFormat) {
    return natives.nativeImageSetup(i);
  }

  @Implementation(minSdk = U.SDK_INT, maxSdk = U.SDK_INT)
  protected Object nativeImageSetup(Object i) {
    // Note: reverted to Q-S API
    return natives.nativeImageSetup((Image) i);
  }

  /** We use a class initializer to allow the native code to cache some field offsets. */
  @Implementation(maxSdk = U.SDK_INT)
  protected static void nativeClassInit() {
    DefaultNativeRuntimeLoader.injectAndLoad();
    ImageReaderNatives.nativeClassInit();
  }

  @ForType(ImageReader.class)
  interface ImageReaderReflector {
    @Accessor("mNativeContext")
    void setMemberNativeContext(long mNativeContext);
  }

  /** Shadow picker for {@link ImageReader}. */
  public static final class Picker extends GraphicsShadowPicker<Object> {
    public Picker() {
      super(ShadowImageReader.class, ShadowNativeImageReader.class);
    }

    @Override
    protected int getMinApiLevel() {
      return S;
    }
  }
}