diff --git a/annotations/src/main/java/org/robolectric/annotation/ClassName.java b/annotations/src/main/java/org/robolectric/annotation/ClassName.java
new file mode 100644
index 00000000000..7f6b2c5611f
--- /dev/null
+++ b/annotations/src/main/java/org/robolectric/annotation/ClassName.java
@@ -0,0 +1,28 @@
+package org.robolectric.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicate a real class name of method's input parameter.
+ *
+ *
For some important Android framework's shadow class, we might bring new APIs to current shadow
+ * class, but these APIs might be added from newer SDK version, and it will cause compiling error
+ * when using these shadow classes with lower compileSdk. We can use this annotation and Object type
+ * to avoid compiling error but with implicit type checking.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface ClassName {
+ /**
+ * The class name intended for this parameter.
+ *
+ *
Use the value as returned from {@link Class#getName()}, not {@link
+ * Class#getCanonicalName()}; e.g. {@code Foo$Bar} instead of {@code Foo.Bar}.
+ */
+ String value() default "";
+}
diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java
index 51953fdc9b1..cc8a268b538 100644
--- a/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java
+++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java
@@ -8,6 +8,7 @@
import static org.robolectric.util.reflector.Reflector.reflector;
import com.google.auto.service.AutoService;
+import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -21,6 +22,7 @@
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Priority;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.ReflectorObject;
import org.robolectric.sandbox.ShadowMatcher;
@@ -291,9 +293,16 @@ private Method findShadowMethod(
Class> shadowClass) {
Method method = findShadowMethodDeclaredOnClass(shadowClass, name, types);
- if (method == null && shadowInfo.looseSignatures) {
- Class>[] genericTypes = MethodType.genericMethodType(types.length).parameterArray();
- method = findShadowMethodDeclaredOnClass(shadowClass, name, genericTypes);
+ if (method == null) {
+ // If user sets looseSignatures for shadow class, we will try to find method with generic
+ // types again.
+ if (shadowInfo.looseSignatures) {
+ Class>[] genericTypes = MethodType.genericMethodType(types.length).parameterArray();
+ method = findShadowMethodDeclaredOnClass(shadowClass, name, genericTypes);
+ } else {
+ // Otherwise, we will try to find method with ClassName annotation that can match signature.
+ method = findShadowMethodWithClassNameDeclaredOnClass(shadowClass, name, types);
+ }
}
if (method != null) {
@@ -317,6 +326,76 @@ private Method findShadowMethod(
return method;
}
+ private ClassName finClassNameAnnotation(Annotation[] annotations) {
+ for (Annotation annotation : annotations) {
+ if (ClassName.class.isAssignableFrom(annotation.annotationType())) {
+ return (ClassName) annotation;
+ }
+ }
+ return null;
+ }
+
+ private boolean hasClassNameAnnotation(Annotation[][] annotations) {
+ for (Annotation[] parameterAnnotations : annotations) {
+ for (Annotation annotation : parameterAnnotations) {
+ if (ClassName.class.isAssignableFrom(annotation.annotationType())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private Method findShadowMethodWithClassNameDeclaredOnClass(
+ Class> shadowClass, String methodName, Class>[] paramClasses) {
+ // We don't process the method without input parameters now.
+ if (paramClasses == null || paramClasses.length == 0) {
+ return null;
+ }
+ Method[] methods = shadowClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (method == null
+ || !method.getName().equals(methodName)
+ || method.getParameterCount() != paramClasses.length
+ || !isValidShadowMethod(method)) {
+ continue;
+ }
+ Class>[] parameterTypes = method.getParameterTypes();
+ Annotation[][] allAnnotations = method.getParameterAnnotations();
+ if (!hasClassNameAnnotation(allAnnotations)) {
+ continue;
+ }
+ boolean matched = true;
+ for (int i = 0; i < parameterTypes.length; i++) {
+ // If method's parameter type is superclass of input parameter, we can pass checking for
+ // this parameter.
+ if (parameterTypes[i].isAssignableFrom(paramClasses[i])) {
+ continue;
+ }
+ if (allAnnotations.length <= i) {
+ matched = false;
+ break;
+ }
+ ClassName className = finClassNameAnnotation(allAnnotations[i]);
+ try {
+ if (className != null
+ && Class.forName(className.value()).isAssignableFrom(paramClasses[i])) {
+ continue;
+ }
+ } catch (ClassNotFoundException ignored) {
+ // Do nothing
+ }
+ matched = false;
+ break;
+ }
+ // TODO identify why above logic will affect __constructor__ without ClassName
+ if (matched) {
+ return method;
+ }
+ }
+ return null;
+ }
+
private Method findShadowMethodDeclaredOnClass(
Class> shadowClass, String methodName, Class>[] paramClasses) {
try {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java
index 47f7306a4ae..be8c9ca1008 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java
@@ -76,7 +76,7 @@
import org.robolectric.util.reflector.WithType;
@SuppressWarnings("NewApi")
-@Implements(value = Activity.class, looseSignatures = true)
+@Implements(value = Activity.class)
public class ShadowActivity extends ShadowContextThemeWrapper {
@RealObject protected Activity realActivity;
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java
index 9d4f6ab1188..d496874779c 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java
@@ -38,7 +38,7 @@
import org.robolectric.util.reflector.ForType;
import org.robolectric.util.reflector.Reflector;
-@Implements(value = ActivityThread.class, isInAndroidSdk = false, looseSignatures = true)
+@Implements(value = ActivityThread.class, isInAndroidSdk = false)
public class ShadowActivityThread {
private static ApplicationInfo applicationInfo;
@RealObject protected ActivityThread realActivityThread;
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppIntegrityManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppIntegrityManager.java
index 1065554d327..4d7eaa507a2 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppIntegrityManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppIntegrityManager.java
@@ -13,7 +13,6 @@
@Implements(
value = AppIntegrityManager.class,
minSdk = R,
- looseSignatures = true,
isInAndroidSdk = false)
public class ShadowAppIntegrityManager {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java
index f420031c94c..be4876cd182 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java
@@ -51,6 +51,7 @@
import java.util.Set;
import java.util.stream.IntStream;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -61,7 +62,7 @@
import org.robolectric.util.ReflectionHelpers.ClassParameter;
/** Shadow for {@link AppOpsManager}. */
-@Implements(value = AppOpsManager.class, minSdk = KITKAT, looseSignatures = true)
+@Implements(value = AppOpsManager.class, minSdk = KITKAT)
public class ShadowAppOpsManager {
// OpEntry fields that the shadow doesn't currently allow the test to configure.
@@ -404,18 +405,18 @@ protected int noteProxyOpNoThrow(
@RequiresApi(api = S)
@Implementation(minSdk = S)
protected int noteProxyOpNoThrow(
- Object op, Object attributionSource, Object message, Object ignoredSkipProxyOperation) {
- Preconditions.checkArgument(op instanceof Integer);
+ int op,
+ @ClassName(value = "android.content.AttributionSource ") Object attributionSource,
+ String message,
+ boolean ignoredSkipProxyOperation) {
Preconditions.checkArgument(attributionSource instanceof AttributionSource);
- Preconditions.checkArgument(message == null || message instanceof String);
- Preconditions.checkArgument(ignoredSkipProxyOperation instanceof Boolean);
AttributionSource castedAttributionSource = (AttributionSource) attributionSource;
return noteProxyOpNoThrow(
- (int) op,
+ op,
castedAttributionSource.getNextPackageName(),
castedAttributionSource.getNextUid(),
castedAttributionSource.getNextAttributionTag(),
- (String) message);
+ message);
}
@Implementation
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java
index eb2276c9e02..644bef18f88 100755
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java
@@ -19,6 +19,7 @@
import java.util.HashMap;
import java.util.Objects;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
@@ -42,8 +43,7 @@
value = ApkAssets.class,
minSdk = P,
shadowPicker = Picker.class,
- isInAndroidSdk = false,
- looseSignatures = true)
+ isInAndroidSdk = false)
public class ShadowArscApkAssets9 extends ShadowApkAssets {
// #define ATRACE_TAG ATRACE_TAG_RESOURCES
//
@@ -286,11 +286,15 @@ protected static long nativeLoad(
@Implementation(minSdk = R)
protected static Object nativeLoad(
- Object format, Object javaPath, Object flags, Object assetsProvider) throws IOException {
- boolean system = ((int) flags & PROPERTY_SYSTEM) == PROPERTY_SYSTEM;
- boolean overlay = ((int) flags & PROPERTY_OVERLAY) == PROPERTY_OVERLAY;
- boolean forceSharedLib = ((int) flags & PROPERTY_DYNAMIC) == PROPERTY_DYNAMIC;
- return nativeLoad((String) javaPath, system, forceSharedLib, overlay);
+ int format,
+ String javaPath,
+ int flags,
+ @ClassName(value = "android.content.res.loader.AssetsProvider") Object assetsProvider)
+ throws IOException {
+ boolean system = (flags & PROPERTY_SYSTEM) == PROPERTY_SYSTEM;
+ boolean overlay = (flags & PROPERTY_OVERLAY) == PROPERTY_OVERLAY;
+ boolean forceSharedLib = (flags & PROPERTY_DYNAMIC) == PROPERTY_DYNAMIC;
+ return nativeLoad(javaPath, system, forceSharedLib, overlay);
}
// static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descriptor,
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java
index 183e9f38d2a..acc80aeccaf 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java
@@ -34,13 +34,14 @@
import java.util.List;
import java.util.Map;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.util.ReflectionHelpers;
@SuppressWarnings({"UnusedDeclaration"})
-@Implements(value = AudioManager.class, looseSignatures = true)
+@Implements(value = AudioManager.class)
public class ShadowAudioManager {
public static final int MAX_VOLUME_MUSIC_DTMF = 15;
@@ -637,7 +638,8 @@ public AudioRecordingConfiguration createActiveRecordingConfiguration(
@HiddenApi
@Implementation(minSdk = P)
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- protected int registerAudioPolicy(@NonNull Object audioPolicy) {
+ protected int registerAudioPolicy(
+ @NonNull @ClassName(value = "android.media.audiopolicy.AudioPolicy") Object audioPolicy) {
Preconditions.checkNotNull(audioPolicy, "Illegal null AudioPolicy argument");
AudioPolicy policy = (AudioPolicy) audioPolicy;
String id = getIdForAudioPolicy(audioPolicy);
@@ -651,7 +653,8 @@ protected int registerAudioPolicy(@NonNull Object audioPolicy) {
@HiddenApi
@Implementation(minSdk = Q)
- protected void unregisterAudioPolicy(@NonNull Object audioPolicy) {
+ protected void unregisterAudioPolicy(
+ @NonNull @ClassName(value = "android.media.audiopolicy.AudioPolicy") Object audioPolicy) {
Preconditions.checkNotNull(audioPolicy, "Illegal null AudioPolicy argument");
AudioPolicy policy = (AudioPolicy) audioPolicy;
registeredAudioPolicies.remove(getIdForAudioPolicy(policy));
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java
index 45a5557a6f4..d981569f962 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java
@@ -26,7 +26,7 @@
* other methods are expected run through the real class. The two {@link WriteMode} are treated the
* same.
*/
-@Implements(value = AudioTrack.class, looseSignatures = true)
+@Implements(value = AudioTrack.class)
public class ShadowAudioTrack {
/**
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java
index 863458509af..77f51316e92 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java
@@ -42,6 +42,7 @@
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nullable;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
@@ -54,7 +55,7 @@
import org.robolectric.util.reflector.Static;
@SuppressWarnings({"UnusedDeclaration"})
-@Implements(value = BluetoothAdapter.class, looseSignatures = true)
+@Implements(value = BluetoothAdapter.class)
public class ShadowBluetoothAdapter {
@RealObject private BluetoothAdapter realAdapter;
@@ -121,9 +122,9 @@ protected static BluetoothAdapter getDefaultAdapter() {
return reflector(BluetoothAdapterReflector.class).getDefaultAdapter();
}
- /** Requires LooseSignatures because of {@link AttributionSource} parameter */
@Implementation(minSdk = VERSION_CODES.TIRAMISU)
- protected static Object createAdapter(Object attributionSource) {
+ protected static Object createAdapter(
+ @ClassName(value = "android.content.AttributionSource") Object attributionSource) {
IBluetoothManager service = ReflectionHelpers.createNullProxy(IBluetoothManager.class);
return ReflectionHelpers.callConstructor(
BluetoothAdapter.class,
@@ -319,10 +320,6 @@ protected boolean setName(String name) {
return true;
}
- /**
- * Needs looseSignatures because in Android T the return value of this method was changed from
- * bool to int.
- */
@Implementation
protected Object setScanMode(int scanMode) {
boolean result = true;
@@ -358,10 +355,7 @@ protected int getScanMode() {
return scanMode;
}
- /**
- * Needs looseSignatures because the return value changed from {@code int} to {@link Duration}
- * starting in T.
- */
+ /** In Android T the return value of this method was changed from bool to int. */
@Implementation
protected Object getDiscoverableTimeout() {
if (RuntimeEnvironment.getApiLevel() <= S_V2) {
@@ -371,6 +365,7 @@ protected Object getDiscoverableTimeout() {
}
}
+ /** T return value changed from {@code int} to {@link Duration} starting in T. */
@Implementation(maxSdk = S_V2)
protected void setDiscoverableTimeout(int timeout) {
discoverableTimeout = Duration.ofSeconds(timeout);
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextHubClient.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextHubClient.java
index 4a99909dea3..9e871a4c252 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextHubClient.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextHubClient.java
@@ -12,11 +12,7 @@
import org.robolectric.annotation.Implements;
/** Shadow for {@link ContextHubClient}. */
-@Implements(
- value = ContextHubClient.class,
- minSdk = VERSION_CODES.P,
- isInAndroidSdk = false,
- looseSignatures = true)
+@Implements(value = ContextHubClient.class, minSdk = VERSION_CODES.P, isInAndroidSdk = false)
public class ShadowContextHubClient {
private final List messages = new ArrayList<>();
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManager.java
index 9959ca1600a..f66b0d52d42 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManager.java
@@ -23,6 +23,7 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.Bootstrap;
import org.robolectric.android.internal.DisplayConfig;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -37,7 +38,7 @@
* For tests, display properties may be changed and devices may be added or removed
* programmatically.
*/
-@Implements(value = DisplayManager.class, minSdk = JELLY_BEAN_MR1, looseSignatures = true)
+@Implements(value = DisplayManager.class, minSdk = JELLY_BEAN_MR1)
public class ShadowDisplayManager {
@RealObject private DisplayManager realDisplayManager;
@@ -249,14 +250,17 @@ public void setSaturationLevel(float level) {
@Implementation(minSdk = P)
@HiddenApi
- protected void setBrightnessConfiguration(Object config) {
+ protected void setBrightnessConfiguration(
+ @ClassName(value = "android.hardware.display.BrightnessConfiguration") Object config) {
setBrightnessConfigurationForUser(config, 0, context.getPackageName());
}
@Implementation(minSdk = P)
@HiddenApi
protected void setBrightnessConfigurationForUser(
- Object config, Object userId, Object packageName) {
+ @ClassName(value = "android.hardware.display.BrightnessConfiguration") Object config,
+ int userId,
+ String packageName) {
getShadowDisplayManagerGlobal().setBrightnessConfigurationForUser(config, userId, packageName);
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHardwareRenderer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHardwareRenderer.java
index 7b86dc2f487..f37e38f8761 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHardwareRenderer.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHardwareRenderer.java
@@ -40,6 +40,7 @@ protected static long nCreateProxy(
// need to use loose signatures here to account for signature changes
@Implementation(minSdk = S)
protected static long nCreateProxy(Object translucent, Object rootRenderNode) {
+ // TODO Find an approach to support the same method with disconnected range
return nCreateProxy((boolean) translucent, (long) rootRenderNode);
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImsMmTelManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImsMmTelManager.java
index 59dd70783fc..1ee04482bf6 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImsMmTelManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImsMmTelManager.java
@@ -36,7 +36,6 @@
@Implements(
value = ImsMmTelManager.class,
minSdk = VERSION_CODES.Q,
- looseSignatures = true,
isInAndroidSdk = false)
@SystemApi
public class ShadowImsMmTelManager {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java
index e76b7973cc2..af0d0fa60b0 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java
@@ -74,7 +74,7 @@
import org.robolectric.util.reflector.ForType;
import org.robolectric.util.reflector.WithType;
-@Implements(value = Instrumentation.class, looseSignatures = true)
+@Implements(value = Instrumentation.class)
public class ShadowInstrumentation {
@RealObject private Instrumentation realObject;
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeAllocationRegistry.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeAllocationRegistry.java
index dfe78a2e4ef..edb4d8038f8 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeAllocationRegistry.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeAllocationRegistry.java
@@ -6,14 +6,8 @@
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
-@Implements(value = NativeAllocationRegistry.class, minSdk = N, isInAndroidSdk = false, looseSignatures = true)
+@Implements(value = NativeAllocationRegistry.class, minSdk = N, isInAndroidSdk = false)
public class ShadowNativeAllocationRegistry {
-
- @Implementation
- protected Runnable registerNativeAllocation(Object referent, Object allocator) {
- return () -> {};
- }
-
@Implementation
protected Runnable registerNativeAllocation(Object referent, long nativePtr) {
return () -> {};
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java
index 8fec6464ac7..84403b2f058 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java
@@ -22,6 +22,7 @@
import android.graphics.PathEffect;
import android.graphics.Shader;
import android.graphics.Typeface;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
@@ -31,7 +32,7 @@
import org.robolectric.util.ReflectionHelpers.ClassParameter;
@SuppressWarnings({"UnusedDeclaration"})
-@Implements(value = Paint.class, looseSignatures = true)
+@Implements(value = Paint.class)
public class ShadowPaint {
private int color;
@@ -505,8 +506,11 @@ protected static int nGetFontMetricsInt(
}
@Implementation(minSdk = N, maxSdk = N_MR1)
- protected int nGetFontMetricsInt(Object nativePaint, Object nativeTypeface, Object fmi) {
- return nGetFontMetricsInt((long) nativePaint, (FontMetricsInt) fmi);
+ protected int nGetFontMetricsInt(
+ long nativePaint,
+ long nativeTypeface,
+ @ClassName(value = "android.graphics.Paint#FontMetricsInt") Object fmi) {
+ return nGetFontMetricsInt(nativePaint, (FontMetricsInt) fmi);
}
@Implementation(maxSdk = M)
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindow.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindow.java
index 232132945d1..8891e8d2fff 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindow.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindow.java
@@ -11,11 +11,11 @@
import org.robolectric.annotation.RealObject;
import org.robolectric.util.reflector.ForType;
-/**
- * Shadow for PhoneWindow for APIs 23+
- */
-@Implements(className = "com.android.internal.policy.PhoneWindow", isInAndroidSdk = false,
- minSdk = M, looseSignatures = true)
+/** Shadow for PhoneWindow for APIs 23+ */
+@Implements(
+ className = "com.android.internal.policy.PhoneWindow",
+ isInAndroidSdk = false,
+ minSdk = M)
public class ShadowPhoneWindow extends ShadowWindow {
@SuppressWarnings("UnusedDeclaration")
protected @RealObject Window realWindow;
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindowFor22.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindowFor22.java
index f39f66e693b..6fae3dd26c5 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindowFor22.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindowFor22.java
@@ -8,11 +8,11 @@
import org.robolectric.annotation.Implements;
import org.robolectric.util.reflector.ForType;
-/**
- * Shadow for the API 16-22 PhoneWindow.li
- */
-@Implements(className = "com.android.internal.policy.impl.PhoneWindow", maxSdk = LOLLIPOP_MR1,
- looseSignatures = true, isInAndroidSdk = false)
+/** Shadow for the API 16-22 PhoneWindow.li */
+@Implements(
+ className = "com.android.internal.policy.impl.PhoneWindow",
+ maxSdk = LOLLIPOP_MR1,
+ isInAndroidSdk = false)
public class ShadowPhoneWindowFor22 extends ShadowPhoneWindow {
@Override @Implementation(maxSdk = LOLLIPOP_MR1)
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java
index db47fc850ad..a509370e0fe 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java
@@ -42,6 +42,7 @@
import java.util.Optional;
import java.util.Set;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.ClassName;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -52,7 +53,7 @@
import org.robolectric.util.reflector.ForType;
/** Shadow of PowerManager */
-@Implements(value = PowerManager.class, looseSignatures = true)
+@Implements(value = PowerManager.class)
public class ShadowPowerManager {
@RealObject private PowerManager realPowerManager;
@@ -213,7 +214,9 @@ protected int getCurrentThermalStatus() {
/** This function adds a listener for thermal status change. */
@Implementation(minSdk = Q)
- protected void addThermalStatusListener(Object listener) {
+ protected void addThermalStatusListener(
+ @ClassName(value = "android.os.PowerManager#OnThermalStatusChangedListener")
+ Object listener) {
checkState(
listener instanceof PowerManager.OnThermalStatusChangedListener,
"Listener must implement PowerManager.OnThermalStatusChangedListener");
@@ -227,7 +230,9 @@ public ImmutableSet