From 0ab7c1b1883ba58e72494baaf51fdb31d7e637ec Mon Sep 17 00:00:00 2001 From: utzcoz Date: Sat, 29 Oct 2022 14:49:37 +0800 Subject: [PATCH] Replace looseSignature with WithType Signed-off-by: utzcoz --- .../internal/bytecode/ShadowWrangler.java | 85 ++++++++++++++++++- .../robolectric/shadows/ShadowActivity.java | 2 +- .../shadows/ShadowActivityThread.java | 2 +- .../shadows/ShadowAppOpsManager.java | 15 ++-- .../shadows/ShadowArscApkAssets9.java | 18 ++-- .../shadows/ShadowAudioManager.java | 9 +- .../robolectric/shadows/ShadowAudioTrack.java | 2 +- .../shadows/ShadowBluetoothAdapter.java | 19 ++--- .../shadows/ShadowDisplayManager.java | 10 ++- .../shadows/ShadowHardwareRenderer.java | 1 + .../org/robolectric/shadows/ShadowPaint.java | 10 ++- .../shadows/ShadowPhoneWindow.java | 10 +-- .../shadows/ShadowPhoneWindowFor22.java | 10 +-- .../shadows/ShadowPowerManager.java | 9 +- .../shadows/ShadowRotationWatcherFor22.java | 14 +-- .../shadows/ShadowSensorManager.java | 2 +- .../shadows/ShadowStaticLayout.java | 53 ++++++------ .../shadows/ShadowSystemClock.java | 5 +- .../shadows/ShadowSystemServiceRegistry.java | 5 +- .../shadows/ShadowTelephonyManager.java | 37 ++++---- .../shadows/ShadowThreadedRenderer.java | 6 +- .../shadows/ShadowTimeZoneFinder.java | 3 +- .../shadows/ShadowTimeZoneFinderQ.java | 3 +- .../shadows/ShadowTimeZoneFinderS.java | 6 +- .../shadows/ShadowUsageStatsManager.java | 7 +- .../robolectric/shadows/ShadowUsbManager.java | 12 +-- .../shadows/ShadowWifiManager.java | 13 ++- .../shadows/ShadowWindowManagerGlobal.java | 6 +- 28 files changed, 235 insertions(+), 139 deletions(-) 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 5e03aa945d7..f6bf33b5719 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; @@ -28,6 +29,7 @@ import org.robolectric.util.Function; import org.robolectric.util.PerfStatsCollector; import org.robolectric.util.Util; +import org.robolectric.util.reflector.WithType; /** * ShadowWrangler matches shadowed classes up with corresponding shadows based on a {@link @@ -322,9 +324,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) { @@ -348,6 +357,76 @@ private Method findShadowMethod( return method; } + private WithType findWithTypeAnnotation(Annotation[] annotations) { + for (Annotation annotation : annotations) { + if (WithType.class.isAssignableFrom(annotation.annotationType())) { + return (WithType) annotation; + } + } + return null; + } + + private boolean hasWithTypeAnnotation(Annotation[][] annotations) { + for (Annotation[] parameterAnnotations : annotations) { + for (Annotation annotation : parameterAnnotations) { + if (WithType.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 (!hasWithTypeAnnotation(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; + } + WithType className = findWithTypeAnnotation(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 0e0d4e605f9..6b381d14078 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java @@ -81,7 +81,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 8b55be12417..d8af12ccc18 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java @@ -42,7 +42,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/ShadowAppOpsManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java index 0d36bfc0604..1010c08b94f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java @@ -63,9 +63,10 @@ import org.robolectric.util.ReflectionHelpers.ClassParameter; import org.robolectric.util.reflector.Accessor; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.WithType; /** 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. @@ -416,18 +417,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, + @WithType(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 9ab0887c72a..6a8b1d167b1 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java @@ -28,6 +28,7 @@ import org.robolectric.util.reflector.Direct; import org.robolectric.util.reflector.ForType; import org.robolectric.util.reflector.Static; +import org.robolectric.util.reflector.WithType; // transliterated from // https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_content_res_ApkAssets.cpp @@ -37,8 +38,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 // @@ -150,11 +150,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, + @WithType(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 1aa553fa9c4..4e08e1ac377 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java @@ -49,9 +49,10 @@ import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.reflector.Constructor; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.WithType; @SuppressWarnings({"UnusedDeclaration"}) -@Implements(value = AudioManager.class, looseSignatures = true) +@Implements(value = AudioManager.class) public class ShadowAudioManager { @RealObject AudioManager realAudioManager; @@ -884,7 +885,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 @WithType(value = "android.media.audiopolicy.AudioPolicy") Object audioPolicy) { Preconditions.checkNotNull(audioPolicy, "Illegal null AudioPolicy argument"); AudioPolicy policy = (AudioPolicy) audioPolicy; String id = getIdForAudioPolicy(audioPolicy); @@ -898,7 +900,8 @@ protected int registerAudioPolicy(@NonNull Object audioPolicy) { @HiddenApi @Implementation(minSdk = Q) - protected void unregisterAudioPolicy(@NonNull Object audioPolicy) { + protected void unregisterAudioPolicy( + @NonNull @WithType(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 ecf5f16ea25..54bd428ce91 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioTrack.java @@ -44,7 +44,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 e9d7e4f7bb9..bb8efc2a1be 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java @@ -58,9 +58,10 @@ import org.robolectric.util.reflector.Direct; import org.robolectric.util.reflector.ForType; import org.robolectric.util.reflector.Static; +import org.robolectric.util.reflector.WithType; @SuppressWarnings({"UnusedDeclaration"}) -@Implements(value = BluetoothAdapter.class, looseSignatures = true) +@Implements(value = BluetoothAdapter.class) public class ShadowBluetoothAdapter { @RealObject private BluetoothAdapter realAdapter; @@ -131,9 +132,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( + @WithType(value = "android.content.AttributionSource") Object attributionSource) { IBluetoothManager service = ReflectionHelpers.createDelegatingProxy( IBluetoothManager.class, new BluetoothManagerDelegate()); @@ -145,7 +146,7 @@ protected static Object createAdapter(Object attributionSource) { /** Sets whether the Le Audio is supported or not. Minimum sdk version required is TIRAMISU. */ public void setLeAudioSupported(int supported) { - isLeAudioSupported = supported; + isLeyeAudioSupported = supported; } @Implementation(minSdk = VERSION_CODES.TIRAMISU) @@ -357,10 +358,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; @@ -396,10 +394,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 776f501c304..d4447fef402 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayManager.java @@ -38,12 +38,13 @@ import org.robolectric.util.ReflectionHelpers.ClassParameter; import org.robolectric.util.reflector.Direct; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.WithType; /** * 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; @@ -316,14 +317,17 @@ public void setSaturationLevel(float level) { @Implementation(minSdk = P) @HiddenApi - protected void setBrightnessConfiguration(Object config) { + protected void setBrightnessConfiguration( + @WithType(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) { + @WithType(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/ShadowPaint.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java index d56a7d7e5e9..718995ddd02 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java @@ -30,11 +30,12 @@ import org.robolectric.config.ConfigurationRegistry; import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers.ClassParameter; +import org.robolectric.util.reflector.WithType; import org.robolectric.versioning.AndroidVersions.U; import org.robolectric.versioning.AndroidVersions.V; @SuppressWarnings({"UnusedDeclaration"}) -@Implements(value = Paint.class, looseSignatures = true) +@Implements(value = Paint.class) public class ShadowPaint { private int color; @@ -534,8 +535,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, + @WithType(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 9411ff1c82e..0ebfd2663d5 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindow.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPhoneWindow.java @@ -13,11 +13,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 { protected @RealObject Window realWindow; protected boolean decorFitsSystemWindows = true; 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 9bce4cca6b4..ac0e492d8ec 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java @@ -52,9 +52,10 @@ import org.robolectric.shadow.api.Shadow; import org.robolectric.util.reflector.Accessor; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.WithType; /** Shadow of PowerManager */ -@Implements(value = PowerManager.class, looseSignatures = true) +@Implements(value = PowerManager.class) public class ShadowPowerManager { @RealObject private PowerManager realPowerManager; @@ -220,7 +221,8 @@ protected int getCurrentThermalStatus() { /** This function adds a listener for thermal status change. */ @Implementation(minSdk = Q) - protected void addThermalStatusListener(Object listener) { + protected void addThermalStatusListener( + @WithType(value = "android.os.PowerManager#OnThermalStatusChangedListener") Object listener) { checkState( listener instanceof PowerManager.OnThermalStatusChangedListener, "Listener must implement PowerManager.OnThermalStatusChangedListener"); @@ -234,7 +236,8 @@ public ImmutableSet getThermalStatusListeners() { /** This function removes a listener for thermal status change. */ @Implementation(minSdk = Q) - protected void removeThermalStatusListener(Object listener) { + protected void removeThermalStatusListener( + @WithType(value = "android.os.PowerManager#OnThermalStatusChangedListener") Object listener) { checkState( listener instanceof PowerManager.OnThermalStatusChangedListener, "Listener must implement PowerManager.OnThermalStatusChangedListener"); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRotationWatcherFor22.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRotationWatcherFor22.java index b27c7d61f4d..932ecdf0d35 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRotationWatcherFor22.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRotationWatcherFor22.java @@ -4,16 +4,18 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.util.reflector.WithType; -/** - * Shadow for RotationWatcher for API 16-22 - */ -@Implements(className = "com.android.internal.policy.impl.PhoneWindow$RotationWatcher", - isInAndroidSdk = false, maxSdk = LOLLIPOP_MR1, looseSignatures = true) +/** Shadow for RotationWatcher for API 16-22 */ +@Implements( + className = "com.android.internal.policy.impl.PhoneWindow$RotationWatcher", + isInAndroidSdk = false, + maxSdk = LOLLIPOP_MR1) public class ShadowRotationWatcherFor22 { @Implementation - protected void addWindow(Object phoneWindow) { + protected void addWindow( + @WithType(value = "com.android.internal.policy.impl.PhoneWindow") Object phoneWindow) { // ignore } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java index 13d5d2ec66a..7840df4f409 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java @@ -28,7 +28,7 @@ import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers.ClassParameter; -@Implements(value = SensorManager.class, looseSignatures = true) +@Implements(value = SensorManager.class) public class ShadowSensorManager { public boolean forceListenersToFail = false; private final Multimap sensorMap = diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStaticLayout.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStaticLayout.java index 5a08de4eb16..08fa2239d7b 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStaticLayout.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStaticLayout.java @@ -17,9 +17,10 @@ import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.reflector.Accessor; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.WithType; /** Shadow for android.text.StaticLayout */ -@Implements(value = StaticLayout.class, looseSignatures = true) +@Implements(value = StaticLayout.class) public class ShadowStaticLayout { @ForType(className = "android.text.StaticLayout$LineBreaks") @@ -46,37 +47,37 @@ public static int[] nLineBreakOpportunities( @HiddenApi @Implementation(minSdk = M, maxSdk = O_MR1) public static int nComputeLineBreaks( - Object nativePtr, - Object recycle, - Object recycleBreaks, - Object recycleWidths, - Object recycleFlags, - Object recycleLength) { + long nativePtr, + @WithType(value = "android.text.StaticLayout$LineBreaks") Object recycle, + int[] recycleBreaks, + float[] recycleWidths, + int[] recycleFlags, + int recycleLength) { return 1; } @HiddenApi @Implementation(minSdk = P, maxSdk = P) protected static int nComputeLineBreaks( - Object nativePtr, - Object text, - Object measuredTextPtr, - Object length, - Object firstWidth, - Object firstWidthLineCount, - Object restWidth, - Object variableTabStops, - Object defaultTabStop, - Object indentsOffset, - Object recycle, - Object recycleLength, - Object recycleBreaks, - Object recycleWidths, - Object recycleAscents, - Object recycleDescents, - Object recycleFlags, - Object charWidths) { - reflector(LineBreaksReflector.class, recycle).setBreaks(new int[] {((char[]) text).length}); + long nativePtr, + char[] text, + long measuredTextPtr, + int length, + float firstWidth, + int firstWidthLineCount, + float restWidth, + int[] variableTabStops, + int defaultTabStop, + int indentsOffset, + @WithType(value = "android.text.StaticLayout$LineBreaks") Object recycle, + int recycleLength, + int[] recycleBreaks, + float[] recycleWidths, + float[] recycleAscents, + float[] recycleDescents, + int[] recycleFlags, + float[] charWidths) { + reflector(LineBreaksReflector.class, recycle).setBreaks(new int[] {text.length}); return 1; } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java index bba7005c431..448f14ea976 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java @@ -17,12 +17,11 @@ /** * The shadow API for {@link SystemClock}. * - * The behavior of SystemClock in Robolectric will differ based on the current {@link + *

The behavior of SystemClock in Robolectric will differ based on the current {@link * LooperMode}. See {@link ShadowLegacySystemClock} and {@link ShadowPausedSystemClock} for more * details. */ -@Implements(value = SystemClock.class, shadowPicker = ShadowSystemClock.Picker.class, - looseSignatures = true) +@Implements(value = SystemClock.class, shadowPicker = ShadowSystemClock.Picker.class) public abstract class ShadowSystemClock { protected static boolean networkTimeAvailable = true; private static boolean gnssTimeAvailable = true; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemServiceRegistry.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemServiceRegistry.java index 9ab967edaf6..8003d956dde 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemServiceRegistry.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemServiceRegistry.java @@ -11,11 +11,11 @@ import org.robolectric.annotation.Resetter; import org.robolectric.util.reflector.Accessor; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.WithType; @Implements( className = "android.app.SystemServiceRegistry", isInAndroidSdk = false, - looseSignatures = true, minSdk = Build.VERSION_CODES.M ) public class ShadowSystemServiceRegistry { @@ -128,7 +128,8 @@ public interface _ServiceFetcherN_ extends _ServiceFetcher_ { } @Implementation(minSdk = O) - protected static void onServiceNotFound(/* ServiceNotFoundException */ Object e0) { + protected static void onServiceNotFound( + @WithType(value = "android.os.ServiceManager.ServiceNotFoundException") Object e0) { // otherwise the full stacktrace might be swallowed... Exception e = (Exception) e0; e.printStackTrace(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephonyManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephonyManager.java index 7b2a756b273..ea1a790b55d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephonyManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephonyManager.java @@ -80,10 +80,11 @@ import org.robolectric.annotation.Resetter; import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; +import org.robolectric.util.reflector.WithType; import org.robolectric.versioning.AndroidVersions.U; import org.robolectric.versioning.AndroidVersions.V; -@Implements(value = TelephonyManager.class, looseSignatures = true) +@Implements(value = TelephonyManager.class) public class ShadowTelephonyManager { @RealObject protected TelephonyManager realTelephonyManager; @@ -207,12 +208,13 @@ public Object getBootstrapAuthenticationCallback() { @Implementation(minSdk = S) @HiddenApi public void bootstrapAuthenticationRequest( - Object appType, - Object nafId, - Object securityProtocol, - Object forceBootStrapping, - Object e, - Object callback) { + int appType, + Uri nafId, + @WithType(value = "android.telephony.gba.UaSecurityProtocolIdentifier") + Object securityProtocol, + boolean forceBootStrapping, + Executor e, + @WithType(value = "android.telephony.BootstrapAuthenticationCallback") Object callback) { this.callback = callback; } @@ -263,7 +265,8 @@ public int getEventFlags() { @Implementation(minSdk = S) public void registerTelephonyCallback( - /*Executor*/ Object executor, /*TelephonyCallback*/ Object callback) { + @WithType(value = "java.util.concurrent.Executor") Object executor, + @WithType(value = "android.telephony.TelephonyCallback") Object callback) { Preconditions.checkArgument(executor instanceof Executor); Preconditions.checkArgument(callback instanceof TelephonyCallback); lastTelephonyCallback = callback; @@ -273,15 +276,15 @@ public void registerTelephonyCallback( @Implementation(minSdk = TIRAMISU) protected void registerTelephonyCallback( - /*int*/ Object includeLocationData, /*Executor*/ - Object executor, /*TelephonyCallback*/ - Object callback) { - Preconditions.checkArgument(includeLocationData instanceof Integer); + int includeLocationData, + @WithType(value = "java.util.concurrent.Executor") Object executor, + @WithType(value = "android.telephony.TelephonyCallback") Object callback) { registerTelephonyCallback(executor, callback); } @Implementation(minSdk = S) - public void unregisterTelephonyCallback(/*TelephonyCallback*/ Object callback) { + public void unregisterTelephonyCallback( + @WithType(value = "android.telephony.TelephonyCallback") Object callback) { telephonyCallbackRegistrations.remove(callback); } @@ -737,8 +740,9 @@ public void setAllCellInfo(List allCellInfo) { * TelephonyManager#NETWORK_TYPE_UNKNOWN} if it was never called. */ @Implementation(minSdk = Q) - protected void requestCellInfoUpdate(Object cellInfoExecutor, Object cellInfoCallback) { - Executor executor = (Executor) cellInfoExecutor; + protected void requestCellInfoUpdate( + Executor executor, + @WithType(value = "android.telephony.CellInfoCallback") Object cellInfoCallback) { if (callbackCellInfos == null) { // ignore } else if (requestCellInfoUpdateErrorCode != 0 || requestCellInfoUpdateDetail != null) { @@ -833,7 +837,8 @@ protected void initListener(PhoneStateListener listener, int flags) { } @CallSuper - protected void initTelephonyCallback(Object callback) { + protected void initTelephonyCallback( + @WithType(value = "android.telephony.TelephonyCallback") Object callback) { if (VERSION.SDK_INT < S) { return; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowThreadedRenderer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowThreadedRenderer.java index 7675c9996ff..5d9d24fa355 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowThreadedRenderer.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowThreadedRenderer.java @@ -8,19 +8,19 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; +import org.robolectric.util.reflector.WithType; @Implements( className = "android.view.ThreadedRenderer", isInAndroidSdk = false, - looseSignatures = true, minSdk = O, maxSdk = P) public class ShadowThreadedRenderer { @Implementation protected static Bitmap createHardwareBitmap( - /*RenderNode*/ Object node, /*int*/ Object width, /*int*/ Object height) { - return createHardwareBitmap((int) width, (int) height); + @WithType(value = "android.view.RenderNode") Object node, int width, int height) { + return createHardwareBitmap(width, height); } private static Bitmap createHardwareBitmap(int width, int height) { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java index 926ae6e8d2b..9f1df6aef81 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java @@ -18,8 +18,7 @@ className = "libcore.util.TimeZoneFinder", minSdk = O, maxSdk = P, - isInAndroidSdk = false, - looseSignatures = true) + isInAndroidSdk = false) public class ShadowTimeZoneFinder { private static final String TZLOOKUP_PATH = "/usr/share/zoneinfo/tzlookup.xml"; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderQ.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderQ.java index 97134bd4268..74ee1fa27c0 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderQ.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderQ.java @@ -14,8 +14,7 @@ className = "libcore.timezone.TimeZoneFinder", minSdk = Q, maxSdk = R, - isInAndroidSdk = false, - looseSignatures = true) + isInAndroidSdk = false) public class ShadowTimeZoneFinderQ { @Implementation diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderS.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderS.java index f28a12edfb2..6e5faec5834 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderS.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinderS.java @@ -12,11 +12,7 @@ import org.robolectric.annotation.Implements; /** Shadow for TimeZoneFinder on S or above. */ -@Implements( - value = TimeZoneFinder.class, - minSdk = S, - isInAndroidSdk = false, - looseSignatures = true) +@Implements(value = TimeZoneFinder.class, minSdk = S, isInAndroidSdk = false) public class ShadowTimeZoneFinderS { private static final String TZLOOKUP_PATH = "/usr/share/zoneinfo/tzlookup.xml"; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java index 40dc52690ec..0cb7489b479 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java @@ -45,10 +45,7 @@ import org.robolectric.annotation.Resetter; /** Shadow of {@link UsageStatsManager}. */ -@Implements( - value = UsageStatsManager.class, - minSdk = Build.VERSION_CODES.LOLLIPOP, - looseSignatures = true) +@Implements(value = UsageStatsManager.class, minSdk = Build.VERSION_CODES.LOLLIPOP) public class ShadowUsageStatsManager { private static @StandbyBuckets int currentAppStandbyBucket = UsageStatsManager.STANDBY_BUCKET_ACTIVE; @@ -596,7 +593,7 @@ public void setUsageSource(@UsageSource int usageSource) { @SuppressWarnings("unchecked") @Implementation(minSdk = TIRAMISU) protected Object /* List */ queryBroadcastResponseStats( - @Nullable Object packageName, Object id) { + @Nullable String packageName, long id) { List result = new ArrayList<>(); for (Map.Entry> entry : appBroadcastStats.entrySet()) { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java index 6e7ab58403e..99d21325429 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsbManager.java @@ -30,9 +30,10 @@ import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.WithType; /** Robolectric implementation of {@link android.hardware.usb.UsbManager}. */ -@Implements(value = UsbManager.class, looseSignatures = true) +@Implements(value = UsbManager.class) public class ShadowUsbManager { @RealObject private UsbManager realUsbManager; @@ -261,22 +262,23 @@ public void addPort( @Implementation(minSdk = M) @HiddenApi - protected /* UsbPortStatus */ Object getPortStatus(/* UsbPort */ Object port) { + protected /* UsbPortStatus */ Object getPortStatus( + @WithType(value = "android.hardware.usb.UsbPort") Object port) { return usbPortStatuses.get(port); } @Implementation(minSdk = M) @HiddenApi protected void setPortRoles( - /* UsbPort */ Object port, /* int */ Object powerRole, /* int */ Object dataRole) { + @WithType(value = "android.hardware.usb.UsbPort") Object port, int powerRole, int dataRole) { UsbPortStatus status = usbPortStatuses.get(port); usbPortStatuses.put( (UsbPort) port, (UsbPortStatus) createUsbPortStatus( status.getCurrentMode(), - (int) powerRole, - (int) dataRole, + powerRole, + dataRole, status.getSupportedRoleCombinations())); RuntimeEnvironment.getApplication() .sendBroadcast(new Intent(UsbManager.ACTION_USB_PORT_CHANGED)); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java index 72c0009312b..9f2b7804259 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java @@ -55,9 +55,10 @@ import org.robolectric.annotation.RealObject; import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; +import org.robolectric.util.reflector.WithType; /** Shadow for {@link android.net.wifi.WifiManager}. */ -@Implements(value = WifiManager.class, looseSignatures = true) +@Implements(value = WifiManager.class) @SuppressWarnings("AndroidConcurrentHashMap") public class ShadowWifiManager { private static final int LOCAL_HOST = 2130706433; @@ -580,8 +581,10 @@ public WifiConfiguration getWifiConfiguration(int netId) { @Implementation(minSdk = Q) @HiddenApi - protected void addOnWifiUsabilityStatsListener(Object executorObject, Object listenerObject) { - Executor executor = (Executor) executorObject; + protected void addOnWifiUsabilityStatsListener( + Executor executor, + @WithType(value = "android.net.wifi.WifiManager$OnWifiUsabilityStatsListener") + Object listenerObject) { WifiManager.OnWifiUsabilityStatsListener listener = (WifiManager.OnWifiUsabilityStatsListener) listenerObject; wifiUsabilityStatsListeners.put(listener, executor); @@ -589,7 +592,9 @@ protected void addOnWifiUsabilityStatsListener(Object executorObject, Object lis @Implementation(minSdk = Q) @HiddenApi - protected void removeOnWifiUsabilityStatsListener(Object listenerObject) { + protected void removeOnWifiUsabilityStatsListener( + @WithType(value = "android.net.wifi.WifiManager$OnWifiUsabilityStatsListener") + Object listenerObject) { WifiManager.OnWifiUsabilityStatsListener listener = (WifiManager.OnWifiUsabilityStatsListener) listenerObject; wifiUsabilityStatsListeners.remove(listener); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java index 72992fa8078..b0123500715 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java @@ -32,11 +32,7 @@ /** Shadow for {@link WindowManagerGlobal}. */ @SuppressWarnings("unused") // Unused params are implementations of Android SDK methods. -@Implements( - value = WindowManagerGlobal.class, - isInAndroidSdk = false, - minSdk = JELLY_BEAN_MR1, - looseSignatures = true) +@Implements(value = WindowManagerGlobal.class, isInAndroidSdk = false, minSdk = JELLY_BEAN_MR1) public class ShadowWindowManagerGlobal { private static WindowSessionDelegate windowSessionDelegate = new WindowSessionDelegate(); private static IWindowSession windowSession;