[TIMOB-26602] Android: Ti.Media.takePicture() will wrongly assign mp4 extension to image file if camera is configured for MEDIA_TYPE_VIDEO
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Low |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2020-10-22T22:24:47.000+0000 |
Affected Version/s | Release 7.0.0 |
Fix Version/s | Release 9.3.0 |
Components | Android |
Labels | android, camera, engReviewed, overlay, photo |
Reporter | Rodrigo Farfán |
Assignee | Joshua Quick |
Created | 2018-04-07T12:46:45.000+0000 |
Updated | 2020-10-22T22:24:47.000+0000 |
Description
Hi there. Using this code:
Ti.Media.showCamera({
autohide : false,
showControls : false,
overlay : cameraControls.getView(),
saveToPhotoGallery : false,
videoMaximumDuration : 60 * 1000,
mediaTypes : [ Titanium.Media.MEDIA_TYPE_PHOTO, Titanium.Media.MEDIA_TYPE_VIDEO ],
success : function(e) {
Ti.API.info(' e.media.mimeType: ' + e.media.mimeType);
},
error : function(e) {
Ti.API.error(JSON.stringify(e));
},
cancel : function() {
Ti.API.info('Action cancelled');
}
});
And calling Ti.Media.takePicture() from "cameraControls" controller, outputs "video/mp4" in the console, i.e., I've opened the camera for both, taking a photo or a video, but if I take a photo, the callback returns a video mimeType with .mp4 extension.
I've fixed this by commenting an if block in TiCameraActivity.java (package ti.modules.titanium.media):
private static File writeToFile(byte[] data, boolean saveToGallery) throws Throwable
{
try {
File imageFile = null;
if (saveToGallery) {
imageFile = MediaModule.createGalleryImageFile();
} else {
// Save the picture in the internal data directory so it is private to this application.
String extension = ".jpg";
// Rodrigo Farfán (phobeous@gmail.com):
// This has no sense. The only point where this method is called is in jpegCallback and
// video recording creates his own file. So this is absolutely wrong
// Let's comment out next if block
/*
if (mediaType == MEDIA_TYPE_VIDEO) {
extension = ".mp4";
}
*/
imageFile = TiFileFactory.createDataFile("tia", extension);
}
FileOutputStream imageOut = new FileOutputStream(imageFile);
imageOut.write(data);
imageOut.close();
if (saveToGallery) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(imageFile);
mediaScanIntent.setData(contentUri);
Activity activity = TiApplication.getAppCurrentActivity();
activity.sendBroadcast(mediaScanIntent);
}
return imageFile;
} catch (Throwable t) {
throw t;
}
}
Please, review this and consider adding the fix to master branch for future releases.
Best regards
Hello, On Android, you can only do one or the other. If both video and photo types are in the array, then "video" will be favored. Now, some camera apps will let you take a photo while in video mode, but not all camera apps will do this. This is because every Android device manufacturer creates and install their own custom camera app and they don't all behave the same. This is a documentation error. We will update the documentation soon. Sorry for the confusion. Thanks.
Hello Sharif. Sorry but I don't agree you. One of our apps (as many others do also in Android) opens up the camera and let the user take a picture or record a video and this doesn't represent any kind of conflict, at least with an overlay, which ends up opening the TiCameraActivity and depends if you "takePicture" or "startVideoCapture"/"stopVideoCapture". Furthermore, the Ti SDK is totally ready to perform this behaviour and our app is doing absolutely fine, at least using showCamera with an overlay, which makes use of the TiCameraActivity (I haven't tested without an overlay). On the other hand, this is not only a documentation issue, as the user takes a picture but the SDK returns a JPG file, but with a wrong mimeType and extensions, i.e., the picture is actually taken and returned to listener, but wrong notified by the callback (wrong extension and mimeType). So if you finally decide to disable this useful feature on Android, you should also fix in the code, disabling (via exception or so) the takePicture method if the video type is in the array and disabling startVideoCapture/stopVideoCapture if the image type is in the array (and also updating the documentation). Anyhow, we're going to go on with our modification because we really need this feature in our app. Thanks.
Same issue on my side.
[~rfarfan] Hi, can you please attach a fully working sample app? I want to try to reproduce the issue locally but don't have all related code it seems.
Hello Rene. Please, download sample project from link and replace guid with a new one https://www.dropbox.com/s/s00n7pllp67tcuk/ti-ac-5695.zip?dl=0 Once deployed on a device (I've tested in Galaxy S6 and S8) you'll watch in console that the JSON printed states the following: "mediaType": "public.video" and inside "media" property, you'll see "mimeType": "image/jpeg", but with wrong "nativePath": "file:///data/user/0/es.codecorp.ac5695/app_appdata/tia1523290744135.mp4" Of course tiaxxxxxxxxxxxx.mp4, as it's a dynamic generated name. Media property returns the proper mimeType (is TiMimeTypeHelper responsibility) but the extension is wrong. In fact, the file is actually a JPEG image. I hope this clarifies what I'm reporting.
[~rfarfan] It's currently being discussed internally, we will let you know asap!
Thanks Hans. IMHO, the SDK has the ability to return both videos and pictures, what is great. We're using in one of our apps. The sample code is an excerpt of our code. When longpressing the button, we start video recording and on touchEnd we finish videoRecording. You can test this method in popular apps like Snapchat, Facebook messenger, ... So that's why I'd like to support this feature in Ti.
Your
mediaType
property is set up toMEDIA_TYPE_PHOTO
andMEDIA_TYPE_VIDEO
. iOS supports multiple media types like this, but unfortunately Android does not. At least with the installed camera app or other 3rd party camera apps. Shariff is completely right about this. This is a limitation with Android's native intents where it can only be set to one action, either photo or video selection. If you specify both, then Titanium will end up favoringMEDIA_TYPE_VIDEO
when showing the installed camera app. The only way to support both is for us to do it ourselves via our own internal camera app, such as our Titanium camera overlay. However, this is not a feature we currently support. Currently, your only option is to specify one or the other on Android.It's caused by this: https://github.com/appcelerator/titanium_mobile/blob/master/android/modules/media/src/java/ti/modules/titanium/media/MediaModule.java#L272 If the
mediaTypes
containsMEDIA_TYPE_VIDEO
it will default to.mp4
This is a known limitation, we need to update our docs until we can provider a PR to fix this.Sorry but Ti is currently supporting both media types in Android. There's no problem about this and we are effectively using in our app (of course with an overlay). The issue is that it's returning the wrong extension for the blob and mediaType. Sincerely, I can't see where's the problem. As I suggested when I registered this issue, the only thing to do is to comment a single line if block in TiCameraActivity and you can take a picture or record a video. If you need the full sample performing this feature, just let me know and I'll update the project to add photo on tap & video on longpress (like Snapchat does).
PR (master): https://github.com/appcelerator/titanium_mobile/pull/12143
FR Passed for this ticket.
Verified the fix with SDK 9.3.0.v20201022111908. Closing.