[image_picker] fix camera on Android 11 (#3194)
diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md
index f9c7640..9d89389 100644
--- a/packages/image_picker/image_picker/CHANGELOG.md
+++ b/packages/image_picker/image_picker/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.3+2
+
+* Fix using Camera as image source on Android 11+
+
## 0.8.3+1
* Fixed README Example.
@@ -26,6 +30,7 @@
* Fix image picker causing a crash when the cache directory is deleted.
## 0.8.1+2
+
* Update the example app to support the multi-image feature.
## 0.8.1+1
diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java
index 8b904f5..dbd0f70 100644
--- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java
+++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java
@@ -6,6 +6,7 @@
import android.Manifest;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -88,7 +89,6 @@
private final ImageResizer imageResizer;
private final ImagePickerCache cache;
private final PermissionManager permissionManager;
- private final IntentResolver intentResolver;
private final FileUriResolver fileUriResolver;
private final FileUtils fileUtils;
private CameraDevice cameraDevice;
@@ -101,10 +101,6 @@
boolean needRequestCameraPermission();
}
- interface IntentResolver {
- boolean resolveActivity(Intent intent);
- }
-
interface FileUriResolver {
Uri resolveFileProviderUriForFile(String fileProviderName, File imageFile);
@@ -148,12 +144,6 @@
return ImagePickerUtils.needRequestCameraPermission(activity);
}
},
- new IntentResolver() {
- @Override
- public boolean resolveActivity(Intent intent) {
- return intent.resolveActivity(activity.getPackageManager()) != null;
- }
- },
new FileUriResolver() {
@Override
public Uri resolveFileProviderUriForFile(String fileProviderName, File file) {
@@ -190,7 +180,6 @@
final MethodCall methodCall,
final ImagePickerCache cache,
final PermissionManager permissionManager,
- final IntentResolver intentResolver,
final FileUriResolver fileUriResolver,
final FileUtils fileUtils) {
this.activity = activity;
@@ -200,7 +189,6 @@
this.pendingResult = result;
this.methodCall = methodCall;
this.permissionManager = permissionManager;
- this.intentResolver = intentResolver;
this.fileUriResolver = fileUriResolver;
this.fileUtils = fileUtils;
this.cache = cache;
@@ -291,13 +279,6 @@
useFrontCamera(intent);
}
- boolean canTakePhotos = intentResolver.resolveActivity(intent);
-
- if (!canTakePhotos) {
- finishWithError("no_available_camera", "No cameras available for taking pictures.");
- return;
- }
-
File videoFile = createTemporaryWritableVideoFile();
pendingCameraMediaUri = Uri.parse("file:" + videoFile.getAbsolutePath());
@@ -305,7 +286,18 @@
intent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri);
grantUriPermissions(intent, videoUri);
- activity.startActivityForResult(intent, REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA);
+ try {
+ activity.startActivityForResult(intent, REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA);
+ } catch (ActivityNotFoundException e) {
+ try {
+ // If we can't delete the file again here, there's not really anything we can do about it.
+ //noinspection ResultOfMethodCallIgnored
+ videoFile.delete();
+ } catch (SecurityException exception) {
+ exception.printStackTrace();
+ }
+ finishWithError("no_available_camera", "No cameras available for taking pictures.");
+ }
}
public void chooseImageFromGallery(MethodCall methodCall, MethodChannel.Result result) {
@@ -371,13 +363,6 @@
useFrontCamera(intent);
}
- boolean canTakePhotos = intentResolver.resolveActivity(intent);
-
- if (!canTakePhotos) {
- finishWithError("no_available_camera", "No cameras available for taking pictures.");
- return;
- }
-
File imageFile = createTemporaryWritableImageFile();
pendingCameraMediaUri = Uri.parse("file:" + imageFile.getAbsolutePath());
@@ -385,7 +370,18 @@
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
grantUriPermissions(intent, imageUri);
- activity.startActivityForResult(intent, REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA);
+ try {
+ activity.startActivityForResult(intent, REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA);
+ } catch (ActivityNotFoundException e) {
+ try {
+ // If we can't delete the file again here, there's not really anything we can do about it.
+ //noinspection ResultOfMethodCallIgnored
+ imageFile.delete();
+ } catch (SecurityException exception) {
+ exception.printStackTrace();
+ }
+ finishWithError("no_available_camera", "No cameras available for taking pictures.");
+ }
}
private File createTemporaryWritableImageFile() {
diff --git a/packages/image_picker/image_picker/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java
index 1b55a75..ebd58d0 100644
--- a/packages/image_picker/image_picker/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java
+++ b/packages/image_picker/image_picker/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java
@@ -7,7 +7,9 @@
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -16,6 +18,7 @@
import android.Manifest;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -42,7 +45,6 @@
@Mock MethodCall mockMethodCall;
@Mock MethodChannel.Result mockResult;
@Mock ImagePickerDelegate.PermissionManager mockPermissionManager;
- @Mock ImagePickerDelegate.IntentResolver mockIntentResolver;
@Mock FileUtils mockFileUtils;
@Mock Intent mockIntent;
@Mock ImagePickerCache cache;
@@ -164,7 +166,6 @@
@Test
public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermission() {
when(mockPermissionManager.needRequestCameraPermission()).thenReturn(false);
- when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true);
ImagePickerDelegate delegate = createDelegate();
delegate.takeImageWithCamera(mockMethodCall, mockResult);
@@ -178,7 +179,6 @@
public void
takeImageWithCamera_WhenHasCameraPermission_AndAnActivityCanHandleCameraIntent_LaunchesTakeWithCameraIntent() {
when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true);
- when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true);
ImagePickerDelegate delegate = createDelegate();
delegate.takeImageWithCamera(mockMethodCall, mockResult);
@@ -192,8 +192,9 @@
public void
takeImageWithCamera_WhenHasCameraPermission_AndNoActivityToHandleCameraIntent_FinishesWithNoCamerasAvailableError() {
when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true);
- when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(false);
-
+ doThrow(ActivityNotFoundException.class)
+ .when(mockActivity)
+ .startActivityForResult(any(Intent.class), anyInt());
ImagePickerDelegate delegate = createDelegate();
delegate.takeImageWithCamera(mockMethodCall, mockResult);
@@ -205,7 +206,6 @@
@Test
public void takeImageWithCamera_WritesImageToCacheDirectory() {
when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true);
- when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true);
ImagePickerDelegate delegate = createDelegate();
delegate.takeImageWithCamera(mockMethodCall, mockResult);
@@ -231,7 +231,6 @@
@Test
public void
onRequestTakeVideoPermissionsResult_WhenCameraPermissionGranted_LaunchesTakeVideoWithCameraIntent() {
- when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true);
ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
delegate.onRequestPermissionsResult(
@@ -247,7 +246,6 @@
@Test
public void
onRequestTakeImagePermissionsResult_WhenCameraPermissionGranted_LaunchesTakeWithCameraIntent() {
- when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true);
ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
delegate.onRequestPermissionsResult(
@@ -379,7 +377,6 @@
null,
cache,
mockPermissionManager,
- mockIntentResolver,
mockFileUriResolver,
mockFileUtils);
}
@@ -393,7 +390,6 @@
mockMethodCall,
cache,
mockPermissionManager,
- mockIntentResolver,
mockFileUriResolver,
mockFileUtils);
}
diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml
index e67e79f..e167d8a 100755
--- a/packages/image_picker/image_picker/pubspec.yaml
+++ b/packages/image_picker/image_picker/pubspec.yaml
@@ -3,7 +3,7 @@
library, and taking new pictures with the camera.
repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
-version: 0.8.3+1
+version: 0.8.3+2
environment:
sdk: ">=2.12.0 <3.0.0"