From 929733b8913311f2cfd504937268a8a1d22f4f9a Mon Sep 17 00:00:00 2001 From: Serge Huijben Date: Wed, 4 Mar 2015 20:33:21 -0500 Subject: [PATCH] CB-8235 android: Fix crash when selecting images from DropBox with spaces in path (close #65) --- src/android/FileHelper.java | 131 ++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 29 deletions(-) diff --git a/src/android/FileHelper.java b/src/android/FileHelper.java index 24ced59..59f890e 100644 --- a/src/android/FileHelper.java +++ b/src/android/FileHelper.java @@ -6,9 +6,7 @@ to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -18,8 +16,14 @@ */ package org.apache.cordova.camera; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.CursorLoader; import android.database.Cursor; import android.net.Uri; +import android.os.Build; +import android.provider.DocumentsContract; +import android.provider.MediaStore; import android.webkit.MimeTypeMap; import org.apache.cordova.CordovaInterface; @@ -43,27 +47,19 @@ public class FileHelper { * @return the full path to the file */ @SuppressWarnings("deprecation") - public static String getRealPath(String uriString, CordovaInterface cordova) { + public static String getRealPath(Uri uri, CordovaInterface cordova) { String realPath = null; - if (uriString.startsWith("content://")) { - String[] proj = { _DATA }; - Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null); - int column_index = cursor.getColumnIndexOrThrow(_DATA); - cursor.moveToFirst(); - realPath = cursor.getString(column_index); - if (realPath == null) { - LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString); - } - } else if (uriString.startsWith("file://")) { - realPath = uriString.substring(7); - if (realPath.startsWith("/android_asset/")) { - LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString); - realPath = null; - } - } else { - realPath = uriString; - } + if (Build.VERSION.SDK_INT < 11) + realPath = FileHelper.getRealPathFromURI_BelowAPI11(cordova.getActivity(), uri); + + // SDK >= 11 && SDK < 19 + else if (Build.VERSION.SDK_INT < 19) + realPath = FileHelper.getRealPathFromURI_API11to18(cordova.getActivity(), uri); + + // SDK > 19 (Android 4.4) + else + realPath = FileHelper.getRealPathFromURI_API19(cordova.getActivity(), uri); return realPath; } @@ -76,8 +72,74 @@ public class FileHelper { * @param cordova the current application context * @return the full path to the file */ - public static String getRealPath(Uri uri, CordovaInterface cordova) { - return FileHelper.getRealPath(uri.toString(), cordova); + public static String getRealPath(String uriString, CordovaInterface cordova) { + return FileHelper.getRealPath(Uri.parse(uriString), cordova); + } + + @SuppressLint("NewApi") + public static String getRealPathFromURI_API19(Context context, Uri uri) { + String filePath = ""; + try { + String wholeID = DocumentsContract.getDocumentId(uri); + + // Split at colon, use second item in the array + String id = wholeID.indexOf(":") > -1 ? wholeID.split(":")[1] : wholeID.indexOf(";") > -1 ? wholeID + .split(";")[1] : wholeID; + + String[] column = { MediaStore.Images.Media.DATA }; + + // where id is equal to + String sel = MediaStore.Images.Media._ID + "=?"; + + Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, + sel, new String[] { id }, null); + + int columnIndex = cursor.getColumnIndex(column[0]); + + if (cursor.moveToFirst()) { + filePath = cursor.getString(columnIndex); + } + cursor.close(); + } catch (Exception e) { + filePath = ""; + } + return filePath; + } + + @SuppressLint("NewApi") + public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) { + String[] proj = { MediaStore.Images.Media.DATA }; + String result = null; + + try { + CursorLoader cursorLoader = new CursorLoader(context, contentUri, proj, null, null, null); + Cursor cursor = cursorLoader.loadInBackground(); + + if (cursor != null) { + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + result = cursor.getString(column_index); + } + } catch (Exception e) { + result = null; + } + return result; + } + + public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) { + String[] proj = { MediaStore.Images.Media.DATA }; + String result = null; + + try { + Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + result = cursor.getString(column_index); + + } catch (Exception e) { + result = null; + } + return result; } /** @@ -88,25 +150,36 @@ public class FileHelper { * @return an input stream into the data at the given URI or null if given an invalid URI string * @throws IOException */ - public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException { + public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) + throws IOException { + InputStream returnValue = null; if (uriString.startsWith("content")) { Uri uri = Uri.parse(uriString); - return cordova.getActivity().getContentResolver().openInputStream(uri); + returnValue = cordova.getActivity().getContentResolver().openInputStream(uri); } else if (uriString.startsWith("file://")) { int question = uriString.indexOf("?"); if (question > -1) { - uriString = uriString.substring(0,question); + uriString = uriString.substring(0, question); } if (uriString.startsWith("file:///android_asset/")) { Uri uri = Uri.parse(uriString); String relativePath = uri.getPath().substring(15); - return cordova.getActivity().getAssets().open(relativePath); + returnValue = cordova.getActivity().getAssets().open(relativePath); } else { - return new FileInputStream(getRealPath(uriString, cordova)); + // might still be content so try that first + try { + returnValue = cordova.getActivity().getContentResolver().openInputStream(Uri.parse(uriString)); + } catch (Exception e) { + returnValue = null; + } + if (returnValue == null) { + returnValue = new FileInputStream(getRealPath(uriString, cordova)); + } } } else { - return new FileInputStream(getRealPath(uriString, cordova)); + returnValue = new FileInputStream(uriString); } + return returnValue; } /**