From 2f21321980debea740df621eb7324be7460ec3bb Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 2 Mar 2023 11:47:25 -0800 Subject: [PATCH] [ci+various] Partially enable javac warning checks (#3293) Since our existing `gradlew lint` check doesn't catch all warnings (notably, deprecation warnings, but also others like raw values), this: - Configures our plugin example apps to enable `-Xlint:all -Werror` for the javac for the plugin project, so that we also get javac lint coverage in CI. This is done in the example app so that it won't affect plugin clients. - Adds a check to `lint-android` that the example is configured this way, so that we don't forget to set it up when adding new plugins (or re-generating plugin examples from template). Where it was trivial for me to just fix existing violations, I did so in this PR. For the rest that had violations, I commented out the enabling of the flags, with a TODO. Normally we would do this kind of thing with a `script/configs` file to opt packages out of a new check, but since this is part of an existing check rather than a whole new command, doing it that way would disable `gradlew lint` for those packages as well. Making a whole new command seemed more complex for the long term, so this seemed like the best short term option. We should try to remove as many of these opt-outs as possible ASAP. Part of https://github.com/flutter/flutter/issues/91868 --- .../example/android/build.gradle | 14 ++++ .../ProcessCameraProviderHostApiImpl.java | 4 +- .../flutter/plugins/camerax/PreviewTest.java | 9 ++- .../camerax/ProcessCameraProviderTest.java | 1 + .../plugins/camerax/SystemServicesTest.java | 6 +- .../example/android/build.gradle | 12 ++++ .../espresso/example/android/build.gradle | 14 ++++ .../FlutterLifecycleAdapterTest.java | 10 ++- .../example/android/build.gradle | 12 ++++ .../google_maps_flutter_android/CHANGELOG.md | 4 ++ .../flutter/plugins/googlemaps/Convert.java | 8 +-- .../example/android/build.gradle | 14 ++++ .../google_maps_flutter_android/pubspec.yaml | 2 +- .../googlesignin/GoogleSignInTest.java | 15 ++++- .../example/android/build.gradle | 12 ++++ .../image_picker_android/CHANGELOG.md | 3 +- .../imagepicker/ImagePickerDelegate.java | 28 ++++---- .../imagepicker/ImagePickerPlugin.java | 6 +- .../plugins/imagepicker/ImagePickerUtils.java | 2 + .../imagepicker/ImagePickerCacheTest.java | 19 ++++-- .../imagepicker/ImagePickerDelegateTest.java | 11 ++- .../imagepicker/ImagePickerPluginTest.java | 55 +++++++++------ .../plugins/imagepicker/ImageResizerTest.java | 12 +++- .../example/android/build.gradle | 12 ++++ .../image_picker_android/pubspec.yaml | 2 +- .../example/android/build.gradle | 14 ++++ .../local_auth_android/CHANGELOG.md | 3 +- .../plugins/localauth/LocalAuthPlugin.java | 3 +- .../plugins/localauth/LocalAuthTest.java | 10 ++- .../example/android/build.gradle | 12 ++++ .../local_auth_android/pubspec.yaml | 2 +- .../example/android/build.gradle | 12 ++++ .../example/android/build.gradle | 12 ++++ .../example/android/build.gradle | 12 ++++ .../example/android/build.gradle | 12 ++++ .../example/android/build.gradle | 14 ++++ .../example/android/build.gradle | 14 ++++ script/tool/lib/src/lint_android_command.dart | 32 +++++++++ .../tool/test/lint_android_command_test.dart | 67 +++++++++++++++++++ 39 files changed, 436 insertions(+), 70 deletions(-) diff --git a/packages/camera/camera_android/example/android/build.gradle b/packages/camera/camera_android/example/android/build.gradle index c21bff8e0a2..e54be495b41 100644 --- a/packages/camera/camera_android/example/android/build.gradle +++ b/packages/camera/camera_android/example/android/build.gradle @@ -27,3 +27,17 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":camera_android") { + tasks.withType(JavaCompile) { + // TODO(stuartmorgan): Enable this. See + // https://github.com/flutter/flutter/issues/91868 + //options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java index e7036e7090c..b8c91a8c1ae 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java @@ -120,9 +120,7 @@ public Long bindToLifecycle( instanceManager.getInstance(((Number) useCaseIds.get(i)).longValue())); } - Camera camera = - processCameraProvider.bindToLifecycle( - (LifecycleOwner) lifecycleOwner, cameraSelector, useCases); + Camera camera = processCameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCases); final CameraFlutterApiImpl cameraFlutterApi = new CameraFlutterApiImpl(binaryMessenger, instanceManager); diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/PreviewTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/PreviewTest.java index 9cb4e910dbb..b76a4c91842 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/PreviewTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/PreviewTest.java @@ -30,6 +30,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -107,7 +108,6 @@ public void setSurfaceProviderTest_createsSurfaceProviderAndReturnsTextureEntryI final ArgumentCaptor surfaceProviderCaptor = ArgumentCaptor.forClass(Preview.SurfaceProvider.class); final ArgumentCaptor surfaceCaptor = ArgumentCaptor.forClass(Surface.class); - final ArgumentCaptor consumerCaptor = ArgumentCaptor.forClass(Consumer.class); // Test that surface provider was set and the surface texture ID was returned. assertEquals(previewHostApi.setSurfaceProvider(previewIdentifier), surfaceTextureEntryId); @@ -136,7 +136,9 @@ public void createSurfaceProvider_createsExpectedPreviewSurfaceProvider() { .thenReturn(mockSystemServicesFlutterApi); final ArgumentCaptor surfaceCaptor = ArgumentCaptor.forClass(Surface.class); - final ArgumentCaptor consumerCaptor = ArgumentCaptor.forClass(Consumer.class); + @SuppressWarnings("unchecked") + final ArgumentCaptor> consumerCaptor = + ArgumentCaptor.forClass(Consumer.class); Preview.SurfaceProvider previewSurfaceProvider = previewHostApi.createSurfaceProvider(mockSurfaceTexture); @@ -183,7 +185,8 @@ public void createSurfaceProvider_createsExpectedPreviewSurfaceProvider() { .thenReturn(SurfaceRequest.Result.RESULT_INVALID_SURFACE); capturedConsumer.accept(mockSurfaceRequestResult); verify(mockSurface).release(); - verify(mockSystemServicesFlutterApi).sendCameraError(anyString(), any(Reply.class)); + verify(mockSystemServicesFlutterApi) + .sendCameraError(anyString(), ArgumentMatchers.>any()); } @Test diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java index 47b4ed6ad26..7efd4576c20 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java @@ -66,6 +66,7 @@ public void getInstanceTest() { new ProcessCameraProviderHostApiImpl(mockBinaryMessenger, testInstanceManager, context); final ListenableFuture processCameraProviderFuture = spy(Futures.immediateFuture(processCameraProvider)); + @SuppressWarnings("unchecked") final GeneratedCameraXLibrary.Result mockResult = mock(GeneratedCameraXLibrary.Result.class); diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/SystemServicesTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/SystemServicesTest.java index eb36c452ec3..562fbe8b526 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/SystemServicesTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/SystemServicesTest.java @@ -24,6 +24,7 @@ import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -43,6 +44,7 @@ public void requestCameraPermissionsTest() { mock(CameraPermissionsManager.class); final Activity mockActivity = mock(Activity.class); final PermissionsRegistry mockPermissionsRegistry = mock(PermissionsRegistry.class); + @SuppressWarnings("unchecked") final Result mockResult = mock(Result.class); final Boolean enableAudio = false; @@ -65,7 +67,7 @@ public void requestCameraPermissionsTest() { eq(enableAudio), resultCallbackCaptor.capture()); - ResultCallback resultCallback = (ResultCallback) resultCallbackCaptor.getValue(); + ResultCallback resultCallback = resultCallbackCaptor.getValue(); // Test no error data is sent upon permissions request success. resultCallback.onResult(null, null); @@ -130,7 +132,7 @@ public void deviceOrientationChangeTest() { deviceOrientationChangeCallback.onChange(DeviceOrientation.PORTRAIT_DOWN); verify(systemServicesFlutterApi) .sendDeviceOrientationChangedEvent( - eq(DeviceOrientation.PORTRAIT_DOWN.toString()), any(Reply.class)); + eq(DeviceOrientation.PORTRAIT_DOWN.toString()), ArgumentMatchers.>any()); // Test that the DeviceOrientationManager starts listening for device orientation changes. verify(mockDeviceOrientationManager).start(); diff --git a/packages/camera/camera_android_camerax/example/android/build.gradle b/packages/camera/camera_android_camerax/example/android/build.gradle index 8640e4de86a..7c909c6116c 100644 --- a/packages/camera/camera_android_camerax/example/android/build.gradle +++ b/packages/camera/camera_android_camerax/example/android/build.gradle @@ -29,3 +29,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":camera_android_camerax") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/espresso/example/android/build.gradle b/packages/espresso/example/android/build.gradle index c21bff8e0a2..10fc8d91f5f 100644 --- a/packages/espresso/example/android/build.gradle +++ b/packages/espresso/example/android/build.gradle @@ -27,3 +27,17 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":espresso") { + tasks.withType(JavaCompile) { + // TODO(stuartmorgan): Enable this. See + // https://github.com/flutter/flutter/issues/91868 + //options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java index 08bb3d7266e..9a6bfb7da5b 100644 --- a/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java +++ b/packages/flutter_plugin_android_lifecycle/android/src/test/java/io/flutter/embedding/engine/plugins/lifecycle/FlutterLifecycleAdapterTest.java @@ -11,6 +11,7 @@ import androidx.lifecycle.Lifecycle; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.PluginRegistry; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -19,9 +20,16 @@ public class FlutterLifecycleAdapterTest { @Mock Lifecycle lifecycle; + AutoCloseable mockCloseable; + @Before public void setUp() { - MockitoAnnotations.initMocks(this); + mockCloseable = MockitoAnnotations.openMocks(this); + } + + @After + public void tearDown() throws Exception { + mockCloseable.close(); } @Test diff --git a/packages/flutter_plugin_android_lifecycle/example/android/build.gradle b/packages/flutter_plugin_android_lifecycle/example/android/build.gradle index c21bff8e0a2..8b3d2202775 100644 --- a/packages/flutter_plugin_android_lifecycle/example/android/build.gradle +++ b/packages/flutter_plugin_android_lifecycle/example/android/build.gradle @@ -27,3 +27,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":flutter_plugin_android_lifecycle") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index fc0771d214f..0607df422e8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.4.8 + +* Fixes compilation warnings. + ## 2.4.7 * Updates annotation dependency. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 22c8f4d24be..78c7dc2428c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -25,7 +25,6 @@ import com.google.android.gms.maps.model.RoundCap; import com.google.android.gms.maps.model.SquareCap; import com.google.android.gms.maps.model.Tile; -import io.flutter.view.FlutterMain; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -50,15 +49,16 @@ private static BitmapDescriptor toBitmapDescriptor(Object o) { case "fromAsset": if (data.size() == 2) { return BitmapDescriptorFactory.fromAsset( - FlutterMain.getLookupKeyForAsset(toString(data.get(1)))); + io.flutter.view.FlutterMain.getLookupKeyForAsset(toString(data.get(1)))); } else { return BitmapDescriptorFactory.fromAsset( - FlutterMain.getLookupKeyForAsset(toString(data.get(1)), toString(data.get(2)))); + io.flutter.view.FlutterMain.getLookupKeyForAsset( + toString(data.get(1)), toString(data.get(2)))); } case "fromAssetImage": if (data.size() == 3) { return BitmapDescriptorFactory.fromAsset( - FlutterMain.getLookupKeyForAsset(toString(data.get(1)))); + io.flutter.view.FlutterMain.getLookupKeyForAsset(toString(data.get(1)))); } else { throw new IllegalArgumentException( "'fromAssetImage' Expected exactly 3 arguments, got: " + data.size()); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/android/build.gradle b/packages/google_maps_flutter/google_maps_flutter_android/example/android/build.gradle index c21bff8e0a2..538fd31e3eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/android/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/android/build.gradle @@ -27,3 +27,17 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":google_maps_flutter_android") { + tasks.withType(JavaCompile) { + // TODO(stuartmorgan): Enable this. See + // https://github.com/flutter/flutter/issues/91868 + //options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index 44feff58e34..2e02e0253b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.4.7 +version: 2.4.8 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java index 78568460c9e..cbd2e40c433 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -41,18 +42,23 @@ public class GoogleSignInTest { @Mock Context mockContext; @Mock Resources mockResources; @Mock Activity mockActivity; - @Mock PluginRegistry.Registrar mockRegistrar; @Mock BinaryMessenger mockMessenger; @Spy MethodChannel.Result result; @Mock GoogleSignInWrapper mockGoogleSignIn; @Mock GoogleSignInAccount account; @Mock GoogleSignInClient mockClient; @Mock Task mockSignInTask; + + @SuppressWarnings("deprecation") + @Mock + PluginRegistry.Registrar mockRegistrar; + private GoogleSignInPlugin plugin; + private AutoCloseable mockCloseable; @Before public void setUp() { - MockitoAnnotations.initMocks(this); + mockCloseable = MockitoAnnotations.openMocks(this); when(mockRegistrar.messenger()).thenReturn(mockMessenger); when(mockRegistrar.context()).thenReturn(mockContext); when(mockRegistrar.activity()).thenReturn(mockActivity); @@ -62,6 +68,11 @@ public void setUp() { plugin.setUpRegistrar(mockRegistrar); } + @After + public void tearDown() throws Exception { + mockCloseable.close(); + } + @Test public void requestScopes_ResultErrorIfAccountIsNull() { MethodCall methodCall = new MethodCall("requestScopes", null); diff --git a/packages/google_sign_in/google_sign_in_android/example/android/build.gradle b/packages/google_sign_in/google_sign_in_android/example/android/build.gradle index c21bff8e0a2..c10d0fa9485 100644 --- a/packages/google_sign_in/google_sign_in_android/example/android/build.gradle +++ b/packages/google_sign_in/google_sign_in_android/example/android/build.gradle @@ -27,3 +27,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":google_sign_in_android") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md index 3b85783c81b..03935b9b47e 100644 --- a/packages/image_picker/image_picker_android/CHANGELOG.md +++ b/packages/image_picker/image_picker_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.8.5+9 +* Fixes compilation warnings. * Updates compileSdkVersion to 33. ## 0.8.5+8 diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index b95fc69ff6b..006eb3dad47 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -31,12 +31,6 @@ import java.util.Map; import java.util.UUID; -enum CameraDevice { - REAR, - - FRONT -} - /** * A delegate class doing the heavy lifting for the plugin. * @@ -86,6 +80,11 @@ public class ImagePickerDelegate @VisibleForTesting static final int REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA = 2353; @VisibleForTesting static final int REQUEST_CAMERA_VIDEO_PERMISSION = 2355; + public enum CameraDevice { + REAR, + FRONT + } + @VisibleForTesting final String fileProviderName; private final Activity activity; @@ -222,21 +221,22 @@ void saveStateBeforeResult() { void retrieveLostImage(MethodChannel.Result result) { Map resultMap = cache.getCacheMap(); @SuppressWarnings("unchecked") - ArrayList pathList = (ArrayList) resultMap.get(cache.MAP_KEY_PATH_LIST); + ArrayList pathList = + (ArrayList) resultMap.get(ImagePickerCache.MAP_KEY_PATH_LIST); ArrayList newPathList = new ArrayList<>(); if (pathList != null) { for (String path : pathList) { - Double maxWidth = (Double) resultMap.get(cache.MAP_KEY_MAX_WIDTH); - Double maxHeight = (Double) resultMap.get(cache.MAP_KEY_MAX_HEIGHT); + Double maxWidth = (Double) resultMap.get(ImagePickerCache.MAP_KEY_MAX_WIDTH); + Double maxHeight = (Double) resultMap.get(ImagePickerCache.MAP_KEY_MAX_HEIGHT); int imageQuality = - resultMap.get(cache.MAP_KEY_IMAGE_QUALITY) == null + resultMap.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY) == null ? 100 - : (int) resultMap.get(cache.MAP_KEY_IMAGE_QUALITY); + : (int) resultMap.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY); newPathList.add(imageResizer.resizeImageIfNeeded(path, maxWidth, maxHeight, imageQuality)); } - resultMap.put(cache.MAP_KEY_PATH_LIST, newPathList); - resultMap.put(cache.MAP_KEY_PATH, newPathList.get(newPathList.size() - 1)); + resultMap.put(ImagePickerCache.MAP_KEY_PATH_LIST, newPathList); + resultMap.put(ImagePickerCache.MAP_KEY_PATH, newPathList.get(newPathList.size() - 1)); } if (resultMap.isEmpty()) { result.success(null); @@ -450,6 +450,8 @@ private File createTemporaryWritableFile(String suffix) { private void grantUriPermissions(Intent intent, Uri imageUri) { PackageManager packageManager = activity.getPackageManager(); + // TODO(stuartmorgan): Add new codepath: https://github.com/flutter/flutter/issues/121816 + @SuppressWarnings("deprecation") List compatibleActivities = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java index 8336a145e93..a1ee1e2f404 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java @@ -342,12 +342,12 @@ public void onMethodCall(MethodCall call, MethodChannel.Result rawResult) { int imageSource; ImagePickerDelegate delegate = activityState.getDelegate(); if (call.argument("cameraDevice") != null) { - CameraDevice device; + ImagePickerDelegate.CameraDevice device; int deviceIntValue = call.argument("cameraDevice"); if (deviceIntValue == CAMERA_DEVICE_FRONT) { - device = CameraDevice.FRONT; + device = ImagePickerDelegate.CameraDevice.FRONT; } else { - device = CameraDevice.REAR; + device = ImagePickerDelegate.CameraDevice.REAR; } delegate.setCameraDevice(device); } diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java index ba987892557..5e80258a00d 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerUtils.java @@ -16,6 +16,8 @@ final class ImagePickerUtils { private static boolean isPermissionPresentInManifest(Context context, String permissionName) { try { PackageManager packageManager = context.getPackageManager(); + // TODO(stuartmorgan): Add new codepath: https://github.com/flutter/flutter/issues/121816 + @SuppressWarnings("deprecation") PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java index 92070e7a65c..7d871665978 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java @@ -6,8 +6,8 @@ import static io.flutter.plugins.imagepicker.ImagePickerCache.MAP_KEY_IMAGE_QUALITY; import static io.flutter.plugins.imagepicker.ImagePickerCache.SHARED_PREFERENCES_NAME; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -19,6 +19,7 @@ import io.flutter.plugin.common.MethodCall; import java.util.HashMap; import java.util.Map; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -34,11 +35,13 @@ public class ImagePickerCacheTest { static Map preferenceStorage; + AutoCloseable mockCloseable; + @Before public void setUp() { - MockitoAnnotations.initMocks(this); + mockCloseable = MockitoAnnotations.openMocks(this); - preferenceStorage = new HashMap(); + preferenceStorage = new HashMap(); when(mockActivity.getPackageName()).thenReturn("com.example.test"); when(mockActivity.getPackageManager()).thenReturn(mock(PackageManager.class)); when(mockActivity.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)) @@ -97,19 +100,25 @@ public void setUp() { when(mockPreference.contains(any(String.class))).thenReturn(true); } + @After + public void tearDown() throws Exception { + mockCloseable.close(); + } + @Test public void ImageCache_ShouldBeAbleToSetAndGetQuality() { when(mockMethodCall.argument(MAP_KEY_IMAGE_QUALITY)).thenReturn(IMAGE_QUALITY); ImagePickerCache cache = new ImagePickerCache(mockActivity); cache.saveDimensionWithMethodCall(mockMethodCall); Map resultMap = cache.getCacheMap(); - int imageQuality = (int) resultMap.get(cache.MAP_KEY_IMAGE_QUALITY); + int imageQuality = (int) resultMap.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY); assertThat(imageQuality, equalTo(IMAGE_QUALITY)); when(mockMethodCall.argument(MAP_KEY_IMAGE_QUALITY)).thenReturn(null); cache.saveDimensionWithMethodCall(mockMethodCall); Map resultMapWithDefaultQuality = cache.getCacheMap(); - int defaultImageQuality = (int) resultMapWithDefaultQuality.get(cache.MAP_KEY_IMAGE_QUALITY); + int defaultImageQuality = + (int) resultMapWithDefaultQuality.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY); assertThat(defaultImageQuality, equalTo(100)); } } diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index 3a6fd0c48c0..29302d90bff 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -4,9 +4,9 @@ package io.flutter.plugins.imagepicker; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -63,6 +63,8 @@ public class ImagePickerDelegateTest { ImagePickerDelegate.FileUriResolver mockFileUriResolver; MockedStatic mockStaticFile; + AutoCloseable mockCloseable; + private static class MockFileUriResolver implements ImagePickerDelegate.FileUriResolver { @Override public Uri resolveFileProviderUriForFile(String fileProviderName, File imageFile) { @@ -77,7 +79,7 @@ public void getFullImagePath(Uri imageUri, ImagePickerDelegate.OnPathReadyListen @Before public void setUp() { - MockitoAnnotations.initMocks(this); + mockCloseable = MockitoAnnotations.openMocks(this); mockStaticFile = Mockito.mockStatic(File.class); mockStaticFile @@ -108,8 +110,9 @@ public void setUp() { } @After - public void tearDown() { + public void tearDown() throws Exception { mockStaticFile.close(); + mockCloseable.close(); } @Test @@ -388,6 +391,7 @@ public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_Stores delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_OK, mockIntent); + @SuppressWarnings("unchecked") ArgumentCaptor> pathListCapture = ArgumentCaptor.forClass(ArrayList.class); verify(cache, times(1)).saveResult(pathListCapture.capture(), any(), any()); assertEquals("pathFromUri", pathListCapture.getValue().get(0)); @@ -503,6 +507,7 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes ImagePickerDelegate mockDelegate = createDelegate(); + @SuppressWarnings("unchecked") ArgumentCaptor> valueCapture = ArgumentCaptor.forClass(Map.class); doNothing().when(mockResult).success(valueCapture.capture()); diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java index 36452479776..328c964c860 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java @@ -4,10 +4,12 @@ package io.flutter.plugins.imagepicker; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -29,10 +31,9 @@ import java.io.File; import java.util.HashMap; import java.util.Map; +import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -43,8 +44,6 @@ public class ImagePickerPluginTest { private static final String PICK_MULTI_IMAGE = "pickMultiImage"; private static final String PICK_VIDEO = "pickVideo"; - @Rule public ExpectedException exception = ExpectedException.none(); - @SuppressWarnings("deprecation") @Mock io.flutter.plugin.common.PluginRegistry.Registrar mockRegistrar; @@ -59,15 +58,22 @@ public class ImagePickerPluginTest { ImagePickerPlugin plugin; + AutoCloseable mockCloseable; + @Before public void setUp() { - MockitoAnnotations.initMocks(this); + mockCloseable = MockitoAnnotations.openMocks(this); when(mockRegistrar.context()).thenReturn(mockApplication); when(mockActivityBinding.getActivity()).thenReturn(mockActivity); when(mockPluginBinding.getApplicationContext()).thenReturn(mockApplication); plugin = new ImagePickerPlugin(mockImagePickerDelegate, mockActivity); } + @After + public void tearDown() throws Exception { + mockCloseable.close(); + } + @Test public void onMethodCall_WhenActivityIsNull_FinishesWithForegroundActivityRequiredError() { MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_GALLERY); @@ -81,18 +87,22 @@ public void onMethodCall_WhenActivityIsNull_FinishesWithForegroundActivityRequir @Test public void onMethodCall_WhenCalledWithUnknownMethod_ThrowsException() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Unknown method test"); - plugin.onMethodCall(new MethodCall("test", null), mockResult); + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + () -> plugin.onMethodCall(new MethodCall("test", null), mockResult)); + assertEquals(e.getMessage(), "Unknown method test"); verifyNoInteractions(mockImagePickerDelegate); verifyNoInteractions(mockResult); } @Test public void onMethodCall_WhenCalledWithUnknownImageSource_ThrowsException() { - exception.expect(IllegalArgumentException.class); - exception.expectMessage("Invalid image source: -1"); - plugin.onMethodCall(buildMethodCall(PICK_IMAGE, -1), mockResult); + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + () -> plugin.onMethodCall(buildMethodCall(PICK_IMAGE, -1), mockResult)); + assertEquals(e.getMessage(), "Invalid image source: -1"); verifyNoInteractions(mockImagePickerDelegate); verifyNoInteractions(mockResult); } @@ -124,39 +134,39 @@ public void onMethodCall_WhenSourceIsCamera_InvokesTakeImageWithCamera() { @Test public void onMethodCall_PickingImage_WhenSourceIsCamera_InvokesTakeImageWithCamera_RearCamera() { MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); - HashMap arguments = (HashMap) call.arguments; + HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 0); plugin.onMethodCall(call, mockResult); - verify(mockImagePickerDelegate).setCameraDevice(eq(CameraDevice.REAR)); + verify(mockImagePickerDelegate).setCameraDevice(eq(ImagePickerDelegate.CameraDevice.REAR)); } @Test public void onMethodCall_PickingImage_WhenSourceIsCamera_InvokesTakeImageWithCamera_FrontCamera() { MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); - HashMap arguments = (HashMap) call.arguments; + HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 1); plugin.onMethodCall(call, mockResult); - verify(mockImagePickerDelegate).setCameraDevice(eq(CameraDevice.FRONT)); + verify(mockImagePickerDelegate).setCameraDevice(eq(ImagePickerDelegate.CameraDevice.FRONT)); } @Test public void onMethodCall_PickingVideo_WhenSourceIsCamera_InvokesTakeImageWithCamera_RearCamera() { MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); - HashMap arguments = (HashMap) call.arguments; + HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 0); plugin.onMethodCall(call, mockResult); - verify(mockImagePickerDelegate).setCameraDevice(eq(CameraDevice.REAR)); + verify(mockImagePickerDelegate).setCameraDevice(eq(ImagePickerDelegate.CameraDevice.REAR)); } @Test public void onMethodCall_PickingVideo_WhenSourceIsCamera_InvokesTakeImageWithCamera_FrontCamera() { MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); - HashMap arguments = (HashMap) call.arguments; + HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 1); plugin.onMethodCall(call, mockResult); - verify(mockImagePickerDelegate).setCameraDevice(eq(CameraDevice.FRONT)); + verify(mockImagePickerDelegate).setCameraDevice(eq(ImagePickerDelegate.CameraDevice.FRONT)); } @Test @@ -217,4 +227,9 @@ private MethodCall buildMethodCall(String method, final int source) { private MethodCall buildMethodCall(String method) { return new MethodCall(method, null); } + + @SuppressWarnings("unchecked") + private HashMap getArgumentMap(MethodCall call) { + return (HashMap) call.arguments; + } } diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java index 73cfef9e88e..a3710038379 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java @@ -4,13 +4,14 @@ package io.flutter.plugins.imagepicker; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.File; import java.io.IOException; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -28,9 +29,11 @@ public class ImageResizerTest { File externalDirectory; Bitmap originalImageBitmap; + AutoCloseable mockCloseable; + @Before public void setUp() throws IOException { - MockitoAnnotations.initMocks(this); + mockCloseable = MockitoAnnotations.openMocks(this); imageFile = new File(getClass().getClassLoader().getResource("pngImage.png").getFile()); originalImageBitmap = BitmapFactory.decodeFile(imageFile.getPath()); TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -39,6 +42,11 @@ public void setUp() throws IOException { resizer = new ImageResizer(externalDirectory, new ExifDataCopier()); } + @After + public void tearDown() throws Exception { + mockCloseable.close(); + } + @Test public void onResizeImageIfNeeded_WhenQualityIsNull_ShoultNotResize_ReturnTheUnscaledFile() { String outoutFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, null, null); diff --git a/packages/image_picker/image_picker_android/example/android/build.gradle b/packages/image_picker/image_picker_android/example/android/build.gradle index e29a4431f2a..ac83e877323 100755 --- a/packages/image_picker/image_picker_android/example/android/build.gradle +++ b/packages/image_picker/image_picker_android/example/android/build.gradle @@ -27,3 +27,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":image_picker_android") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml index cd606752e31..de62db1d86d 100755 --- a/packages/image_picker/image_picker_android/pubspec.yaml +++ b/packages/image_picker/image_picker_android/pubspec.yaml @@ -3,7 +3,7 @@ description: Android implementation of the image_picker plugin. repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.8.5+8 +version: 0.8.5+9 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/in_app_purchase/in_app_purchase_android/example/android/build.gradle b/packages/in_app_purchase/in_app_purchase_android/example/android/build.gradle index c21bff8e0a2..5bb3499d4ff 100644 --- a/packages/in_app_purchase/in_app_purchase_android/example/android/build.gradle +++ b/packages/in_app_purchase/in_app_purchase_android/example/android/build.gradle @@ -27,3 +27,17 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":in_app_purchase_android") { + tasks.withType(JavaCompile) { + // TODO(stuartmorgan): Enable this. See + // https://github.com/flutter/flutter/issues/91868 + //options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/local_auth/local_auth_android/CHANGELOG.md b/packages/local_auth/local_auth_android/CHANGELOG.md index b74748c3f2e..bf94a765a78 100644 --- a/packages/local_auth/local_auth_android/CHANGELOG.md +++ b/packages/local_auth/local_auth_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 1.0.20 +* Fixes compilation warnings. * Updates compileSdkVersion to 33. ## 1.0.19 diff --git a/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java b/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java index e545df01e7c..d724b38c0a7 100644 --- a/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java +++ b/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java @@ -26,7 +26,6 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry; -import io.flutter.plugin.common.PluginRegistry.Registrar; import io.flutter.plugins.localauth.AuthenticationHelper.AuthCompletionHandler; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; @@ -78,7 +77,7 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) { * io.flutter.plugin.common.BinaryMessenger}. */ @SuppressWarnings("deprecation") - public static void registerWith(Registrar registrar) { + public static void registerWith(PluginRegistry.Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME); final LocalAuthPlugin plugin = new LocalAuthPlugin(); plugin.activity = registrar.activity(); diff --git a/packages/local_auth/local_auth_android/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java b/packages/local_auth/local_auth_android/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java index 7279a3c49af..38c3908f4e7 100644 --- a/packages/local_auth/local_auth_android/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java +++ b/packages/local_auth/local_auth_android/android/src/test/java/io/flutter/plugins/localauth/LocalAuthTest.java @@ -238,7 +238,7 @@ public void onDetachedFromActivity_ShouldReleaseActivity() { final FlutterPluginBinding mockPluginBinding = mock(FlutterPluginBinding.class); final FlutterEngine mockFlutterEngine = mock(FlutterEngine.class); - when(mockPluginBinding.getFlutterEngine()).thenReturn(mockFlutterEngine); + mockDeprecatedFlutterEngineGetter(mockPluginBinding, mockFlutterEngine); DartExecutor mockDartExecutor = mock(DartExecutor.class); when(mockFlutterEngine.getDartExecutor()).thenReturn(mockDartExecutor); @@ -399,11 +399,17 @@ private void setPluginActivity(LocalAuthPlugin plugin, Activity activity) { final ActivityPluginBinding mockActivityBinding = mock(ActivityPluginBinding.class); final FlutterEngine mockFlutterEngine = mock(FlutterEngine.class); final DartExecutor mockDartExecutor = mock(DartExecutor.class); - when(mockPluginBinding.getFlutterEngine()).thenReturn(mockFlutterEngine); + mockDeprecatedFlutterEngineGetter(mockPluginBinding, mockFlutterEngine); when(mockFlutterEngine.getDartExecutor()).thenReturn(mockDartExecutor); when(mockActivityBinding.getActivity()).thenReturn(activity); when(mockActivityBinding.getLifecycle()).thenReturn(mockLifecycleReference); plugin.onAttachedToEngine(mockPluginBinding); plugin.onAttachedToActivity(mockActivityBinding); } + + @SuppressWarnings("deprecation") + private void mockDeprecatedFlutterEngineGetter( + FlutterPluginBinding binding, FlutterEngine engine) { + when(binding.getFlutterEngine()).thenReturn(engine); + } } diff --git a/packages/local_auth/local_auth_android/example/android/build.gradle b/packages/local_auth/local_auth_android/example/android/build.gradle index 3593d963655..9455e41996d 100644 --- a/packages/local_auth/local_auth_android/example/android/build.gradle +++ b/packages/local_auth/local_auth_android/example/android/build.gradle @@ -27,3 +27,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":local_auth_android") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/local_auth/local_auth_android/pubspec.yaml b/packages/local_auth/local_auth_android/pubspec.yaml index b668c0e18fb..e1b9fc8a10e 100644 --- a/packages/local_auth/local_auth_android/pubspec.yaml +++ b/packages/local_auth/local_auth_android/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth_android description: Android implementation of the local_auth plugin. repository: https://github.com/flutter/packages/tree/main/packages/local_auth/local_auth_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+local_auth%22 -version: 1.0.19 +version: 1.0.20 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/path_provider/path_provider_android/example/android/build.gradle b/packages/path_provider/path_provider_android/example/android/build.gradle index c21bff8e0a2..3f8bef9e7b6 100644 --- a/packages/path_provider/path_provider_android/example/android/build.gradle +++ b/packages/path_provider/path_provider_android/example/android/build.gradle @@ -27,3 +27,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":path_provider_android") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/quick_actions/quick_actions_android/example/android/build.gradle b/packages/quick_actions/quick_actions_android/example/android/build.gradle index c21bff8e0a2..4215a59005b 100644 --- a/packages/quick_actions/quick_actions_android/example/android/build.gradle +++ b/packages/quick_actions/quick_actions_android/example/android/build.gradle @@ -27,3 +27,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":quick_actions_android") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/shared_preferences/shared_preferences_android/example/android/build.gradle b/packages/shared_preferences/shared_preferences_android/example/android/build.gradle index 21d50697b9e..23a5996a120 100644 --- a/packages/shared_preferences/shared_preferences_android/example/android/build.gradle +++ b/packages/shared_preferences/shared_preferences_android/example/android/build.gradle @@ -29,3 +29,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":shared_preferences_android") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/url_launcher/url_launcher_android/example/android/build.gradle b/packages/url_launcher/url_launcher_android/example/android/build.gradle index c21bff8e0a2..0e900021669 100644 --- a/packages/url_launcher/url_launcher_android/example/android/build.gradle +++ b/packages/url_launcher/url_launcher_android/example/android/build.gradle @@ -27,3 +27,15 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":url_launcher_android") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/video_player/video_player_android/example/android/build.gradle b/packages/video_player/video_player_android/example/android/build.gradle index c21bff8e0a2..4851ea6e2c3 100644 --- a/packages/video_player/video_player_android/example/android/build.gradle +++ b/packages/video_player/video_player_android/example/android/build.gradle @@ -27,3 +27,17 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":video_player_android") { + tasks.withType(JavaCompile) { + // TODO(stuartmorgan): Enable this. See + // https://github.com/flutter/flutter/issues/91868 + //options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/example/android/build.gradle b/packages/webview_flutter/webview_flutter_android/example/android/build.gradle index e29a4431f2a..1942e9d40d7 100644 --- a/packages/webview_flutter/webview_flutter_android/example/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/example/android/build.gradle @@ -27,3 +27,17 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir } + +// Build the plugin project with warnings enabled. This is here rather than +// in the plugin itself to avoid breaking clients that have different +// warnings (e.g., deprecation warnings from a newer SDK than this project +// builds with). +gradle.projectsEvaluated { + project(":webview_flutter_android") { + tasks.withType(JavaCompile) { + // TODO(stuartmorgan): Enable this. See + // https://github.com/flutter/flutter/issues/91868 + //options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} diff --git a/script/tool/lib/src/lint_android_command.dart b/script/tool/lib/src/lint_android_command.dart index eb78ce89168..f146b2d4fbb 100644 --- a/script/tool/lib/src/lint_android_command.dart +++ b/script/tool/lib/src/lint_android_command.dart @@ -60,6 +60,38 @@ class LintAndroidCommand extends PackageLoopingCommand { if (exitCode != 0) { failed = true; } + + // In addition to running the Gradle lint step, also ensure that the + // example project is configured to build with javac lints enabled and + // treated as errors. + final List gradleBuildContents = example + .platformDirectory(FlutterPlatform.android) + .childFile('build.gradle') + .readAsLinesSync(); + // The check here is intentionally somewhat loose, to allow for the + // possibility of variations (e.g., not using Xlint:all in some cases, or + // passing other arguments). + if (!gradleBuildContents.any( + (String line) => line.contains('project(":$packageName")')) || + !gradleBuildContents.any((String line) => + line.contains('options.compilerArgs') && + line.contains('-Xlint') && + line.contains('-Werror'))) { + failed = true; + printError('The example ' + '${getRelativePosixPath(example.directory, from: package.directory)} ' + 'is not configured to treat javac lints and warnings as errors. ' + 'Please add the following to its build.gradle:'); + print(''' +gradle.projectsEvaluated { + project(":${package.directory.basename}") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} +'''); + } } return failed ? PackageResult.fail() : PackageResult.success(); diff --git a/script/tool/test/lint_android_command_test.dart b/script/tool/test/lint_android_command_test.dart index e4a6c5c859e..40ffaf177a7 100644 --- a/script/tool/test/lint_android_command_test.dart +++ b/script/tool/test/lint_android_command_test.dart @@ -39,6 +39,40 @@ void main() { runner.addCommand(command); }); + void writeFakeBuildGradle(RepositoryPackage example, String pluginName, + {bool warningsConfigured = true}) { + final String warningConfig = ''' +gradle.projectsEvaluated { + project(":$pluginName") { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:all" << "-Werror" + } + } +} +'''; + example + .platformDirectory(FlutterPlatform.android) + .childFile('build.gradle') + .writeAsStringSync(''' +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.0.1' + } +} +allprojects { + repositories { + google() + mavenCentral() + } +} +${warningsConfigured ? warningConfig : ''} +'''); + } + test('runs gradle lint', () async { final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, extraFiles: [ @@ -46,6 +80,7 @@ void main() { ], platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); + writeFakeBuildGradle(plugin.getExamples().first, 'plugin1'); final Directory androidDir = plugin.getExamples().first.platformDirectory(FlutterPlatform.android); @@ -83,6 +118,9 @@ void main() { platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); + for (final RepositoryPackage example in plugin.getExamples()) { + writeFakeBuildGradle(example, 'plugin1'); + } final Iterable exampleAndroidDirs = plugin.getExamples().map( (RepositoryPackage example) => @@ -140,6 +178,7 @@ void main() { ], platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); + writeFakeBuildGradle(plugin.getExamples().first, 'plugin1'); final String gradlewPath = plugin .getExamples() @@ -167,6 +206,34 @@ void main() { )); }); + test('fails if javac lint-warnings-as-errors is missing', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin1', packagesDir, extraFiles: [ + 'example/android/gradlew', + ], platformSupport: { + platformAndroid: const PlatformDetails(PlatformSupport.inline) + }); + writeFakeBuildGradle(plugin.getExamples().first, 'plugin1', + warningsConfigured: false); + + Error? commandError; + final List output = await runCapturingPrint( + runner, ['lint-android'], errorHandler: (Error e) { + commandError = e; + }); + + expect(commandError, isA()); + expect( + output, + containsAllInOrder( + [ + contains('The example example is not configured to treat javac ' + 'lints and warnings as errors.'), + contains('The following packages had errors:'), + ], + )); + }); + test('skips non-Android plugins', () async { createFakePlugin('plugin1', packagesDir);