Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-26602] Android: Ti.Media.takePicture() will wrongly assign mp4 extension to image file if camera is configured for MEDIA_TYPE_VIDEO

GitHub Issuen/a
TypeBug
PriorityLow
StatusClosed
ResolutionFixed
Resolution Date2020-10-22T22:24:47.000+0000
Affected Version/sRelease 7.0.0
Fix Version/sRelease 9.3.0
ComponentsAndroid
Labelsandroid, camera, engReviewed, overlay, photo
ReporterRodrigo Farfán
AssigneeJoshua Quick
Created2018-04-07T12:46:45.000+0000
Updated2020-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

Comments

  1. Sharif AbuDarda 2018-04-07

    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.
  2. Rodrigo Farfán 2018-04-08

    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.
  3. Miguel Ángel Castaño 2018-04-08

    Same issue on my side.
  4. Rene Pot 2018-04-09

    [~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.
  5. Rodrigo Farfán 2018-04-09

    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.
  6. Hans Knöchel 2018-04-10

    [~rfarfan] It's currently being discussed internally, we will let you know asap!
  7. Rodrigo Farfán 2018-04-10

    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.
  8. Joshua Quick 2018-04-10

    Your mediaType property is set up to MEDIA_TYPE_PHOTO and MEDIA_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 favoring MEDIA_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.
  9. Gary Mathews 2018-04-10

    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 contains MEDIA_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.
  10. Rodrigo Farfán 2018-04-10

    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).
  11. Joshua Quick 2020-10-01

    PR (master): https://github.com/appcelerator/titanium_mobile/pull/12143
  12. Sohail Saddique 2020-10-08

    FR Passed for this ticket.
  13. Lokesh Choudhary 2020-10-22

    Verified the fix with SDK 9.3.0.v20201022111908. Closing.

JSON Source