Fix Android sharing files without extension (#1646)

This commit is contained in:
Elias Nahum 2018-04-30 11:57:24 -03:00 committed by GitHub
parent 8a152ac1e7
commit aebe22f58d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 4 deletions

View file

@ -7,6 +7,7 @@ import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.content.ContentUris;
import android.content.ContentResolver;
import android.os.Environment;
import android.webkit.MimeTypeMap;
@ -98,6 +99,7 @@ public class RealPathUtil {
cacheDir.mkdirs();
}
String mimeType = getMimeType(uri.getPath());
tmpFile = File.createTempFile("tmp", fileName, cacheDir);
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
@ -182,6 +184,11 @@ public class RealPathUtil {
return getMimeType(file);
}
public static String getMimeTypeFromUri(final Context context, final Uri uri) {
ContentResolver cR = context.getContentResolver();
return cR.getType(uri);
}
public static void deleteTempFiles(final File dir) {
try {
if (dir.isDirectory()) {

View file

@ -126,7 +126,7 @@ public class ShareModule extends ReactContextBaseJavaModule {
map = Arguments.createMap();
text = "file://" + filePath;
map.putString("value", text);
map.putString("type", RealPathUtil.getMimeType(filePath));
map.putString("type", RealPathUtil.getMimeTypeFromUri(currentActivity, uri));
items.pushMap(map);
}
}

View file

@ -3,11 +3,13 @@
import {Platform} from 'react-native';
import RNFetchBlob from 'react-native-fetch-blob';
import mimeDB from 'mime-db';
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
import {DeviceTypes} from 'app/constants/';
const EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
const {DOCUMENTS_PATH, IMAGES_PATH, VIDEOS_PATH} = DeviceTypes;
const DEFAULT_SERVER_MAX_FILE_SIZE = 50 * 1024 * 1024;// 50 Mb
@ -32,6 +34,9 @@ const SUPPORTED_VIDEO_FORMAT = Platform.select({
android: ['video/3gpp', 'video/x-matroska', 'video/mp4', 'video/webm'],
});
const types = {};
const extensions = {};
export function generateId() {
// Implementation taken from http://stackoverflow.com/a/2117523
let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
@ -144,3 +149,69 @@ export const isVideo = (file) => {
return SUPPORTED_VIDEO_FORMAT.includes(mime);
};
/**
* Get the default extension for a MIME type.
*
* @param {string} type
* @return {boolean|string}
*/
export function getExtensionFromMime(type) {
if (!Object.keys(extensions).length) {
populateMaps();
}
if (!type || typeof type !== 'string') {
return false;
}
// TODO: use media-typer
const match = EXTRACT_TYPE_REGEXP.exec(type);
// get extensions
const exts = match && extensions[match[1].toLowerCase()];
if (!exts || !exts.length) {
return false;
}
return exts[0];
}
/**
* Populate the extensions and types maps.
* @private
*/
function populateMaps() {
// source preference (least -> most)
const preference = ['nginx', 'apache', undefined, 'iana']; //eslint-disable-line no-undefined
Object.keys(mimeDB).forEach((type) => {
const mime = mimeDB[type];
const exts = mime.extensions;
if (!exts || !exts.length) {
return;
}
extensions[type] = exts;
for (let i = 0; i < exts.length; i++) {
const extension = exts[i];
if (types[extension]) {
const from = preference.indexOf(mimeDB[types[extension]].source);
const to = preference.indexOf(mime.source);
if (types[extension] !== 'application/octet-stream' &&
(from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) {
continue;
}
}
types[extension] = type;
}
});
}

View file

@ -6,6 +6,7 @@ import {NavigationActions} from 'react-navigation';
import TouchableItem from 'react-navigation/src/views/TouchableItem';
import PropTypes from 'prop-types';
import {intlShape} from 'react-intl';
import {
Image,
NativeModules,
@ -25,6 +26,7 @@ import {getFormattedFileSize, lookupMimeType} from 'mattermost-redux/utils/file_
import PaperPlane from 'app/components/paper_plane';
import mattermostManaged from 'app/mattermost_managed';
import {getExtensionFromMime} from 'app/utils/file';
import {emptyFunction} from 'app/utils/general';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
@ -278,15 +280,20 @@ export default class ExtensionPost extends PureComponent {
break;
default: {
const fullPath = item.value;
const filename = fullPath.replace(/^.*[\\/]/, '');
const extension = filename.split('.').pop();
const fileSize = await RNFetchBlob.fs.stat(fullPath);
let filename = fullPath.replace(/^.*[\\/]/, '');
let extension = filename.split('.').pop();
if (extension === filename) {
extension = getExtensionFromMime(item.type);
filename = `${filename}.${extension}`;
}
totalSize += fileSize.size;
files.push({
extension,
filename,
fullPath,
mimeType: lookupMimeType(filename.toLowerCase()),
mimeType: item.type || lookupMimeType(filename.toLowerCase()),
size: getFormattedFileSize(fileSize),
type: item.type,
});