Android Camera : data intent returns null
The default Android camera application returns a non-null intent only when passing back a thumbnail in the returned Intent. If you pass EXTRA_OUTPUT
with a URI to write to, it will return a null
intent and the picture is in the URI that you passed in.
You can verify this by looking at the camera app's source code on GitHub:
-
https://github.com/android/platform_packages_apps_camera/blob/gingerbread-release/src/com/android/camera/Camera.java#L1186
Bundle newExtras = new Bundle(); if (mCropValue.equals("circle")) { newExtras.putString("circleCrop", "true"); } if (mSaveUri != null) { newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri); } else { newExtras.putBoolean("return-data", true); }
I would guess that you're either passing in EXTRA_OUTPUT
somehow, or the camera app on your phone works differently.
I found an easy answer. it works!!
private void openCameraForResult(int requestCode){
Intent photo = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = Uri.parse("file:///sdcard/photo.jpg");
photo.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(photo,requestCode);
}
if (requestCode == CAMERA_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "photo.jpg");
Uri uri = Uri.fromFile(file);
Bitmap bitmap;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
bitmap = cropAndScale(bitmap, 300); // if you mind scaling
profileImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
if you would like to crop and scale this image
public static Bitmap cropAndScale (Bitmap source, int scale){
int factor = source.getHeight() <= source.getWidth() ? source.getHeight(): source.getWidth();
int longer = source.getHeight() >= source.getWidth() ? source.getHeight(): source.getWidth();
int x = source.getHeight() >= source.getWidth() ?0:(longer-factor)/2;
int y = source.getHeight() <= source.getWidth() ?0:(longer-factor)/2;
source = Bitmap.createBitmap(source, x, y, factor, factor);
source = Bitmap.createScaledBitmap(source, scale, scale, false);
return source;
}
I´ve had experienced this problem, the intent
is not null but the information sent via this intent
is not received in onActionActivit()
This is a better solution using getContentResolver() :
private Uri imageUri;
private ImageView myImageView;
private Bitmap thumbnail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
...
...
myImageview = (ImageView) findViewById(R.id.pic);
values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "MyPicture");
values.put(MediaStore.Images.Media.DESCRIPTION, "Photo taken on " + System.currentTimeMillis());
imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, PICTURE_RESULT);
}
the onActivityResult()
get a bitmap stored by getContentResolver() :
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_TAKE_PHOTO && resultCode == RESULT_OK) {
Bitmap bitmap;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
myImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Check my example in github:
https://github.com/Jorgesys/TakePicture
Simple working camera app avoiding the null intent problem
- all changed code included in this reply; close to android tutorial
I've been spending plenty of time on this issue, so I decided to create an account and share my outcomes with you.
The official android tutorial "Taking Photos Simply" turned out to not quite hold what it promised. The code provided there did not work on my device: a Samsung Galaxy S4 Mini GT-I9195 running android version 4.4.2 / KitKat / API Level 19.
I figured out that the main problem was the following line in the method invoked when capturing the photo (dispatchTakePictureIntent
in the tutorial):
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
It resulted in the intent subsequently catched by onActivityResult
being null.
To solve this problem, I pulled much inspiration out of earlier replies here and some helpful posts on github (mostly this one by deepwinter - big thanks to him; you might want to check out his reply on a closely related post as well).
Following these pleasant pieces of advice, I chose the strategy of deleting the mentioned putExtra
line and doing the corresponding thing of getting back the taken picture from the camera within the onActivityResult() method instead.
The decisive lines of code to get back the bitmap associated with the picture are:
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
I created an exemplary app which just has the ability to take a picture, save it on the SD card and display it. I think this might be helpful to people in the same situation as me when I stumbled on this issue, since the current help suggestions mostly refer to rather extensive github posts which do the thing in question but aren't too easy to oversee for newbies like me. With respect to the file system Android Studio creates per default when creating a new project, I just had to change three files for my purpose:
activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.simpleworkingcameraapp.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="takePicAndDisplayIt"
android:text="Take a pic and display it." />
<ImageView
android:id="@+id/image1"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
MainActivity.java :
package com.example.android.simpleworkingcameraapp;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.Image;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private ImageView image;
static final int REQUEST_TAKE_PHOTO = 1;
String mCurrentPhotoPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image1);
}
// copied from the android development pages; just added a Toast to show the storage location
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmm").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
Toast.makeText(this, mCurrentPhotoPath, Toast.LENGTH_LONG).show();
return image;
}
public void takePicAndDisplayIt(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
File file = null;
try {
file = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
startActivityForResult(intent, REQUEST_TAKE_PHOTO);
}
}
@Override
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
if (requestCode == REQUEST_TAKE_PHOTO && resultcode == RESULT_OK) {
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
image.setImageBitmap(bitmap);
}
}
}
AndroidManifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.simpleworkingcameraapp">
<!--only added paragraph-->
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- only crucial line to add; for me it still worked without the other lines in this paragraph -->
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Note that the solution I found for the problem also led to a simplification of the android manifest file: the changes suggested by the android tutorial in terms of adding a provider are no longer needed since I am not making use of any in my java code. Hence, only few standard lines -mostly regarding permissions- had to be added to the manifest file.
It might additionally be valuable to point out that Android Studio's autoimport may not be capable of handling java.text.SimpleDateFormat
and java.util.Date
. I had to import both of them manually.
Probably because you had something like this?
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri fileUri = CommonUtilities.getTBCameraOutputMediaFileUri();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(takePictureIntent, 2);
However you must not put the extra output into the intent, because then the data goes into the URI instead of the data variable. For that reason, you have to take the two lines in the middle out, so that you have
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 2);
That´s what caused the problem for me, hope that helped.