CB-11625: Files Provider does not work with Android 4.4.4 or lower, and I have no idea why. Working around with CordovaUri

This commit is contained in:
Joe Bowser 2016-10-27 13:37:03 -07:00
parent 61064ae3ed
commit 84f96c1067
2 changed files with 98 additions and 11 deletions

View File

@ -103,7 +103,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
private int targetWidth; // desired width of the image private int targetWidth; // desired width of the image
private int targetHeight; // desired height of the image private int targetHeight; // desired height of the image
private Uri imageUri; // Uri of captured image private CordovaUri imageUri; // Uri of captured image
private int encodingType; // Type of encoding to use private int encodingType; // Type of encoding to use
private int mediaType; // What type of media to retrieve private int mediaType; // What type of media to retrieve
private int destType; // Source type (needs to be saved for the permission handling) private int destType; // Source type (needs to be saved for the permission handling)
@ -292,10 +292,10 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Specify file so that large image is captured and returned // Specify file so that large image is captured and returned
File photo = createCaptureFile(encodingType); File photo = createCaptureFile(encodingType);
this.imageUri = FileProvider.getUriForFile(cordova.getActivity(), this.imageUri = new CordovaUri(FileProvider.getUriForFile(cordova.getActivity(),
applicationId + ".provider", applicationId + ".provider",
photo); photo));
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, this.imageUri); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageUri.getCorrectUri());
//We can write to this URI, this will hopefully allow us to write files to get to the next step //We can write to this URI, this will hopefully allow us to write files to get to the next step
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
@ -471,7 +471,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
String sourcePath = (this.allowEdit && this.croppedUri != null) ? String sourcePath = (this.allowEdit && this.croppedUri != null) ?
FileHelper.stripFileProtocol(this.croppedUri.toString()) : FileHelper.stripFileProtocol(this.croppedUri.toString()) :
getFileNameFromUri(this.imageUri); this.imageUri.getFilePath();
if (this.encodingType == JPEG) { if (this.encodingType == JPEG) {
@ -498,7 +498,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
if (this.allowEdit && this.croppedUri != null) { if (this.allowEdit && this.croppedUri != null) {
writeUncompressedImage(croppedUri, galleryUri); writeUncompressedImage(croppedUri, galleryUri);
} else { } else {
Uri imageUri = Uri.fromFile(new File(getFileNameFromUri(this.imageUri))); Uri imageUri = this.imageUri.getFileUri();
writeUncompressedImage(imageUri, galleryUri); writeUncompressedImage(imageUri, galleryUri);
} }
@ -546,7 +546,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
Uri croppedUri = Uri.fromFile(new File(getFileNameFromUri(this.croppedUri))); Uri croppedUri = Uri.fromFile(new File(getFileNameFromUri(this.croppedUri)));
writeUncompressedImage(croppedUri, uri); writeUncompressedImage(croppedUri, uri);
} else { } else {
Uri imageUri = Uri.fromFile(new File(getFileNameFromUri(this.imageUri))); Uri imageUri = this.imageUri.getFileUri();
writeUncompressedImage(imageUri, uri); writeUncompressedImage(imageUri, uri);
} }
@ -589,7 +589,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
throw new IllegalStateException(); throw new IllegalStateException();
} }
this.cleanup(FILE_URI, this.imageUri, galleryUri, bitmap); this.cleanup(FILE_URI, this.imageUri.getFileUri(), galleryUri, bitmap);
bitmap = null; bitmap = null;
} }
@ -1340,7 +1340,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
} }
if (this.imageUri != null) { if (this.imageUri != null) {
state.putString("imageUri", this.imageUri.toString()); state.putString("imageUri", this.imageUri.getFileUri().toString());
} }
return state; return state;
@ -1364,7 +1364,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
} }
if (state.containsKey("imageUri")) { if (state.containsKey("imageUri")) {
this.imageUri = Uri.parse(state.getString("imageUri")); //I have no idea what type of URI is being passed in
this.imageUri = new CordovaUri(Uri.parse(state.getString("imageUri")));
} }
this.callbackContext = callbackContext; this.callbackContext = callbackContext;
@ -1382,7 +1383,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
* we own the context in this case. * we own the context in this case.
*/ */
private String getFileNameFromUri(Uri uri) { private String getFileNameFromUri(Uri uri) {
String fullUri = uri.toString(); String fullUri = uri.toString();
String partial_path = fullUri.split("external_files")[1]; String partial_path = fullUri.split("external_files")[1];
@ -1391,4 +1391,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
return path; return path;
} }
} }

View File

@ -0,0 +1,85 @@
package org.apache.cordova.camera;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import java.io.File;
/*
* This class exists because Andorid FilesProvider doesn't work on Android 4.4.4 and below and throws
* weird errors. I'm not sure why writing to shared cache directories is somehow verboten, but it is
* and this error is irritating for a Compatibility library to have.
*
*/
public class CordovaUri {
private Uri androidUri;
private String fileName;
private Uri fileUri;
/*
* We always expect a FileProvider string to be passed in for the file that we create
*
*/
CordovaUri (Uri inputUri)
{
//Determine whether the file is a content or file URI
if(inputUri.getScheme().equals("content"))
{
androidUri = inputUri;
fileName = getFileNameFromUri(androidUri);
fileUri = Uri.parse("file://" + fileName);
}
else
{
fileUri = inputUri;
fileName = FileHelper.stripFileProtocol(inputUri.toString());
}
}
public Uri getFileUri()
{
return fileUri;
}
public String getFilePath()
{
return fileName;
}
/*
* This only gets called by takePicture
*/
public Uri getCorrectUri()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
return androidUri;
else
return fileUri;
}
/*
* This is dirty, but it does the job.
*
* Since the FilesProvider doesn't really provide you a way of getting a URL from the file,
* and since we actually need the Camera to create the file for us most of the time, we don't
* actually write the file, just generate the location based on a timestamp, we need to get it
* back from the Intent.
*
* However, the FilesProvider preserves the path, so we can at least write to it from here, since
* we own the context in this case.
*/
private String getFileNameFromUri(Uri uri) {
String fullUri = uri.toString();
String partial_path = fullUri.split("external_files")[1];
File external_storage = Environment.getExternalStorageDirectory();
String path = external_storage.getAbsolutePath() + partial_path;
return path;
}
}