I am building app my first Android app using WebView and Camera features. I have been following the official documentation and I have encounter many problems.
For example Saving Media Files according to the documentation, sample code provided under and I use it as it is provided:
/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
return Uri.fromFile(getOutputMediaFile(type));
}
/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
It works perfectly on a device that I am running Android 5.0.2 but it can not create the directory on Android Android 6.0.1. I was debugging the process and I noticed that it returns null
on this part of the code:
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
I was searching online and I have found similar threads regarding this problem, such as (Why can i not make a directory inside Environment.DIRECTORY_PICTURES?, android environment.directory_pictures not accessible and Android getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) returns path to /storage/emulated/0 instead of pictures path) etc...
On the last thread if you read a comment says:
If you are looking for memory card path you wont get it on all devices. As per official documentation public static String DIRECTORY_PICTURES Standard directory in which to place pictures that are available to the user. you cannot control what path is returned
Which makes sense, this is why I want to use the default, but since it is not working on Android 6.0.1 I was thinking to apply a workaround by specifying which location to save the files. Taken from the official documentation Image capture intent:
MediaStore.EXTRA_OUTPUT - This setting requires a Uri object specifying a path and file name where you'd like to save the picture. This setting is optional but strongly recommended. If you do not specify this value, the camera application saves the requested picture in the default location with a default name, specified in the returned intent's Intent.getData() field.
If I have understand correctly I could specify an alternative file path location, such as mediaFile = File.createTempFile(timeStamp, extension, mWebViewActivity.getExternalCacheDir());
.
This small workaround helped me overcome the problem in Android 6.0.1 and on Android 5.0.2, but the down side is on both cases when I retrieve the data are empty.
Sample of code retrieving data from documentation Receiving camera intent result:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Image captured and saved to fileUri specified in the Intent
Toast.makeText(this, "Image saved to:\n" +
data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
} else {
// Image capture failed, advise user
}
}
if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Video captured and saved to fileUri specified in the Intent
Toast.makeText(this, "Video saved to:\n" +
data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
// User cancelled the video capture
} else {
// Video capture failed, advise user
}
}
}
In case that I have changed the location to save the data from File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp");
to mediaFile = File.createTempFile(timeStamp, extension, mWebViewActivity.getExternalCacheDir());
, both Environments (5.0.2 and 6.0.1) can overcome the problem and "pretend that the work fine". By saying pretend I mean I do not get any errors or the APP is not crashing, but there is a problem.
As the documentation states:
If you do not specify this value, the camera application saves the requested picture in the default location with a default name, specified in the returned intent's Intent.getData() field.
Which is what exactly happens in may case. Both versions can not understand the Uri
that I am using. On 5.0.2 it is able to take the default location and "somehow" completes the process but on 6.0.1 since it can not find the default location, it just takes the picture/video but it does not store it anywhere so it can retrieved and the data are empty.
I have included in my Manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
**Update: ** Adding chooser,
public Intent makeChooserIntent(String title, WebChromeClient.FileChooserParams fileChooserParams) {
Intent galleryIntent = new Intent(Intent.ACTION_CHOOSER, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Intent chooser = Intent.createChooser(galleryIntent, title);
List<Intent> intentActivitiesList = new ArrayList<>();
if (checkCameraHardware(mWebViewActivity.getApplicationContext())) {
Log.d(TAG, "Device has camera.");
//create new Intent
Intent videoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intentActivitiesList.add(imageIntent);
intentActivitiesList.add(videoIntent);
intentActivitiesList.add(fileChooserParams.createIntent());
try {
imageFileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
videoFileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO); // create a file to save the video
} catch (IOException e) {
Log.e(TAG, "Error creating tmp file: " + e);
}
chooser.putExtra(MediaStore.EXTRA_OUTPUT, videoFileUri); // set the image file name
chooser.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high
chooser.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentActivitiesList.toArray(new Parcelable[]{}));
}
return chooser;
}
I think the error comes from the chooser, because is not looking for the correct Uri.
So my question, is this a bug, or I am setting something completely wrong?
Sorry for the long question/post but I tried to explain all problems/solutions that I have applied.
If I debug the retrieved data on Android 5.0.2 if I have changed