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..926375f1b4e 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,7 @@ 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. - */ + /** T return value changed from {@code int} to {@link Duration} starting in T. */ @Implementation protected Object setScanMode(int scanMode) { boolean result = true; @@ -358,10 +356,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) { 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