diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index e3899c340571..3a743340dc6e 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.10.0 +* **Breaking Change** Updates Android camera access permission error codes to be consistent with other platforms. If your app still handles the legacy `cameraPermission` exception, please update it to handle the new permission exception codes that are noted in the README. * Ignores missing return warnings in preparation for [upcoming analysis changes](https://github.com/flutter/flutter/issues/105750). ## 0.9.8+3 diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java index 7d60e0fffa5c..4441751e19cf 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraPermissions.java @@ -23,8 +23,22 @@ interface ResultCallback { void onResult(String errorCode, String errorDescription); } + /** + * Camera access permission errors handled when camera is created. See {@code MethodChannelCamera} + * in {@code camera/camera_platform_interface} for details. + */ + private static final String CAMERA_PERMISSIONS_REQUEST_ONGOING = + "CameraPermissionsRequestOngoing"; + + private static final String CAMERA_PERMISSIONS_REQUEST_ONGOING_MESSAGE = + "Another request is ongoing and multiple requests cannot be handled at once."; + private static final String CAMERA_ACCESS_DENIED = "CameraAccessDenied"; + private static final String CAMERA_ACCESS_DENIED_MESSAGE = "Camera access permission was denied."; + private static final String AUDIO_ACCESS_DENIED = "AudioAccessDenied"; + private static final String AUDIO_ACCESS_DENIED_MESSAGE = "Audio access permission was denied."; + private static final int CAMERA_REQUEST_ID = 9796; - private boolean ongoing = false; + @VisibleForTesting boolean ongoing = false; void requestPermissions( Activity activity, @@ -32,7 +46,9 @@ void requestPermissions( boolean enableAudio, ResultCallback callback) { if (ongoing) { - callback.onResult("cameraPermission", "Camera permission request ongoing"); + callback.onResult( + CAMERA_PERMISSIONS_REQUEST_ONGOING, CAMERA_PERMISSIONS_REQUEST_ONGOING_MESSAGE); + return; } if (!hasCameraPermission(activity) || (enableAudio && !hasAudioPermission(activity))) { permissionsRegistry.addListener( @@ -90,9 +106,9 @@ public boolean onRequestPermissionsResult(int id, String[] permissions, int[] gr alreadyCalled = true; if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { - callback.onResult("cameraPermission", "MediaRecorderCamera permission not granted"); + callback.onResult(CAMERA_ACCESS_DENIED, CAMERA_ACCESS_DENIED_MESSAGE); } else if (grantResults.length > 1 && grantResults[1] != PackageManager.PERMISSION_GRANTED) { - callback.onResult("cameraPermission", "MediaRecorderAudio permission not granted"); + callback.onResult(AUDIO_ACCESS_DENIED, AUDIO_ACCESS_DENIED_MESSAGE); } else { callback.onResult(null, null); } diff --git a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java index ecb96a88f31a..d734a63b15ca 100644 --- a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java +++ b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraPermissionsTest.java @@ -5,9 +5,13 @@ package io.flutter.plugins.camera; import static junit.framework.TestCase.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import android.content.pm.PackageManager; import io.flutter.plugins.camera.CameraPermissions.CameraRequestPermissionsListener; +import io.flutter.plugins.camera.CameraPermissions.ResultCallback; import org.junit.Test; public class CameraPermissionsTest { @@ -24,4 +28,48 @@ public void listener_respondsOnce() { assertEquals(1, calledCounter[0]); } + + @Test + public void callback_respondsWithCameraAccessDenied() { + ResultCallback fakeResultCallback = mock(ResultCallback.class); + CameraRequestPermissionsListener permissionsListener = + new CameraRequestPermissionsListener(fakeResultCallback); + + permissionsListener.onRequestPermissionsResult( + 9796, null, new int[] {PackageManager.PERMISSION_DENIED}); + + verify(fakeResultCallback) + .onResult("CameraAccessDenied", "Camera access permission was denied."); + } + + @Test + public void callback_respondsWithAudioAccessDenied() { + ResultCallback fakeResultCallback = mock(ResultCallback.class); + CameraRequestPermissionsListener permissionsListener = + new CameraRequestPermissionsListener(fakeResultCallback); + + permissionsListener.onRequestPermissionsResult( + 9796, + null, + new int[] {PackageManager.PERMISSION_GRANTED, PackageManager.PERMISSION_DENIED}); + + verify(fakeResultCallback).onResult("AudioAccessDenied", "Audio access permission was denied."); + } + + @Test + public void callback_doesNotRespond() { + ResultCallback fakeResultCallback = mock(ResultCallback.class); + CameraRequestPermissionsListener permissionsListener = + new CameraRequestPermissionsListener(fakeResultCallback); + + permissionsListener.onRequestPermissionsResult( + 9796, + null, + new int[] {PackageManager.PERMISSION_GRANTED, PackageManager.PERMISSION_GRANTED}); + + verify(fakeResultCallback, never()) + .onResult("CameraAccessDenied", "Camera access permission was denied."); + verify(fakeResultCallback, never()) + .onResult("AudioAccessDenied", "Audio access permission was denied."); + } } diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index a1b7a930e228..581780f0d87b 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android description: Android implementation of the camera plugin. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.8+3 +version: 0.10.0 environment: sdk: ">=2.14.0 <3.0.0"