forked from Ivasoft/mattermost-mobile
Handle Image picker permissions (#1064)
This commit is contained in:
@@ -6,8 +6,10 @@ import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
@@ -44,6 +46,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
|
||||
import com.facebook.react.modules.core.PermissionListener;
|
||||
import com.facebook.react.modules.core.PermissionAwareActivity;
|
||||
@@ -196,7 +199,9 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
|
||||
public void doOnCancel()
|
||||
{
|
||||
responseHelper.invokeCancel(callback);
|
||||
if (this.callback != null) {
|
||||
responseHelper.invokeCancel(this.callback);
|
||||
}
|
||||
}
|
||||
|
||||
public void launchCamera()
|
||||
@@ -221,6 +226,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
return;
|
||||
}
|
||||
|
||||
this.callback = callback;
|
||||
this.options = options;
|
||||
|
||||
if (!permissionsCheck(currentActivity, callback, REQUEST_PERMISSIONS_FOR_CAMERA))
|
||||
@@ -251,7 +257,12 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
final File original = createNewFile(reactContext, this.options, false);
|
||||
imageConfig = imageConfig.withOriginalFile(original);
|
||||
|
||||
cameraCaptureURI = RealPathUtil.compatUriFromFile(reactContext, imageConfig.original);
|
||||
if (imageConfig.original != null) {
|
||||
cameraCaptureURI = RealPathUtil.compatUriFromFile(reactContext, imageConfig.original);
|
||||
}else {
|
||||
responseHelper.invokeError(callback, "Couldn't get file path for photo");
|
||||
return;
|
||||
}
|
||||
if (cameraCaptureURI == null)
|
||||
{
|
||||
responseHelper.invokeError(callback, "Couldn't get file path for photo");
|
||||
@@ -266,7 +277,16 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
return;
|
||||
}
|
||||
|
||||
this.callback = callback;
|
||||
// Workaround for Android bug.
|
||||
// grantUriPermission also needed for KITKAT,
|
||||
// see https://code.google.com/p/android/issues/detail?id=76683
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
|
||||
List<ResolveInfo> resInfoList = reactContext.getPackageManager().queryIntentActivities(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
for (ResolveInfo resolveInfo : resInfoList) {
|
||||
String packageName = resolveInfo.activityInfo.packageName;
|
||||
reactContext.grantUriPermission(packageName, cameraCaptureURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -294,6 +314,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
this.callback = callback;
|
||||
|
||||
if (!permissionsCheck(currentActivity, callback, REQUEST_PERMISSIONS_FOR_LIBRARY))
|
||||
{
|
||||
@@ -314,7 +335,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
{
|
||||
requestCode = REQUEST_LAUNCH_IMAGE_LIBRARY;
|
||||
libraryIntent = new Intent(Intent.ACTION_PICK,
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
}
|
||||
|
||||
if (libraryIntent.resolveActivity(reactContext.getPackageManager()) == null)
|
||||
@@ -323,8 +344,6 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
return;
|
||||
}
|
||||
|
||||
this.callback = callback;
|
||||
|
||||
try
|
||||
{
|
||||
currentActivity.startActivityForResult(libraryIntent, requestCode);
|
||||
@@ -571,7 +590,9 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
innerActivity.startActivityForResult(intent, 1);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
if (dialog != null) {
|
||||
dialog.show();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -606,7 +627,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
|
||||
private boolean isCameraAvailable() {
|
||||
return reactContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)
|
||||
|| reactContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
|
||||
|| reactContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
|
||||
}
|
||||
|
||||
private @NonNull String getRealPathFromURI(@NonNull final Uri uri) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {injectIntl, intlShape} from 'react-intl';
|
||||
import {
|
||||
Platform,
|
||||
StyleSheet,
|
||||
@@ -10,21 +11,38 @@ import ImagePicker from 'react-native-image-picker';
|
||||
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
export default class AttachmentButton extends PureComponent {
|
||||
class AttachmentButton extends PureComponent {
|
||||
static propTypes = {
|
||||
blurTextBox: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
uploadFiles: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
attachFileFromCamera = () => {
|
||||
const {formatMessage} = this.props.intl;
|
||||
const options = {
|
||||
quality: 0.7,
|
||||
noData: true,
|
||||
storageOptions: {
|
||||
cameraRoll: true,
|
||||
waitUntilSaved: true
|
||||
},
|
||||
permissionDenied: {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.camera_permission_denied_title',
|
||||
defaultMessage: 'Camera access is required'
|
||||
}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.camera_permission_denied_description',
|
||||
defaultMessage: 'To take photos and videos with your camera, please change your permission settings.'
|
||||
}),
|
||||
reTryTitle: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set Permission'
|
||||
}),
|
||||
okTitle: formatMessage({id: 'mobile.android.permission_denied_dismiss', defaultMessage: 'Dismiss'})
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,9 +56,25 @@ export default class AttachmentButton extends PureComponent {
|
||||
};
|
||||
|
||||
attachFileFromLibrary = () => {
|
||||
const {formatMessage} = this.props.intl;
|
||||
const options = {
|
||||
quality: 0.7,
|
||||
noData: true
|
||||
noData: true,
|
||||
permissionDenied: {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_title',
|
||||
defaultMessage: 'Photo library access is required'
|
||||
}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.photos_permission_denied_description',
|
||||
defaultMessage: 'To upload images from your library, please change your permission settings.'
|
||||
}),
|
||||
reTryTitle: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set Permission'
|
||||
}),
|
||||
okTitle: formatMessage({id: 'mobile.android.permission_denied_dismiss', defaultMessage: 'Dismiss'})
|
||||
}
|
||||
};
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
@@ -57,10 +91,26 @@ export default class AttachmentButton extends PureComponent {
|
||||
};
|
||||
|
||||
attachVideoFromLibraryAndroid = () => {
|
||||
const {formatMessage} = this.props.intl;
|
||||
const options = {
|
||||
quality: 0.7,
|
||||
mediaType: 'video',
|
||||
noData: true
|
||||
noData: true,
|
||||
permissionDenied: {
|
||||
title: formatMessage({
|
||||
id: 'mobile.android.videos_permission_denied_title',
|
||||
defaultMessage: 'Video library access is required'
|
||||
}),
|
||||
text: formatMessage({
|
||||
id: 'mobile.android.videos_permission_denied_description',
|
||||
defaultMessage: 'To upload videos from your library, please change your permission settings.'
|
||||
}),
|
||||
reTryTitle: formatMessage({
|
||||
id: 'mobile.android.permission_denied_retry',
|
||||
defaultMessage: 'Set Permission'
|
||||
}),
|
||||
okTitle: formatMessage({id: 'mobile.android.permission_denied_dismiss', defaultMessage: 'Dismiss'})
|
||||
}
|
||||
};
|
||||
|
||||
ImagePicker.launchImageLibrary(options, (response) => {
|
||||
@@ -70,7 +120,7 @@ export default class AttachmentButton extends PureComponent {
|
||||
|
||||
this.uploadFiles([response]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
uploadFiles = (images) => {
|
||||
this.props.uploadFiles(images);
|
||||
@@ -175,3 +225,5 @@ const style = StyleSheet.create({
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
export default injectIntl(AttachmentButton);
|
||||
|
||||
@@ -1880,6 +1880,14 @@
|
||||
"mobile.advanced_settings.reset_message": "\nThis will reset all offline data and restart the app. You will be automatically logged back in once the app restarts.\n",
|
||||
"mobile.advanced_settings.reset_title": "Reset Cache",
|
||||
"mobile.advanced_settings.title": "Advanced Settings",
|
||||
"mobile.android.camera_permission_denied_title": "Camera access is required",
|
||||
"mobile.android.camera_permission_denied_description": "To take photos and videos with your camera, please change your permission settings.",
|
||||
"mobile.android.photos_permission_denied_title": "Photo library access is required",
|
||||
"mobile.android.photos_permission_denied_description": "To upload images from your library, please change your permission settings.",
|
||||
"mobile.android.videos_permission_denied_title": "Video library access is required",
|
||||
"mobile.android.videos_permission_denied_description": "To upload videos from your library, please change your permission settings.",
|
||||
"mobile.android.permission_denied_retry": "Set permission",
|
||||
"mobile.android.permission_denied_dismiss": "Dismiss",
|
||||
"mobile.channel_drawer.search": "Jump to...",
|
||||
"mobile.channel_info.alertMessageDeleteChannel": "Are you sure you want to delete the {term} {name}?",
|
||||
"mobile.channel_info.alertMessageLeaveChannel": "Are you sure you want to leave the {term} {name}?",
|
||||
|
||||
Reference in New Issue
Block a user