Hi i started to use Camera in Android, as simple as it can get from here.
The problem is after i shoot the photo the file's uri is just null for some reason.
Steps:
I ran the takePhoto() func, my phone's standard camera app starts,
i take a photo, i save it.
My app ran the onActivityResult(...) func as it gets back the control from camera, and the file's uri is just null.
Code:
In my Activity:
/**
* Intent code for capturing a photo
*/
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
/**
*
* Takes a photo
*/
public void takePhoto() {
// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = CameraHelper.getOutputMediaFileUri(CameraHelper.MEDIA_TYPE_IMAGE); // create a file to save the image
Log.i("PHOTO", "file uri is: " + fileUri.toString());
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
// start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
/**
*
* After taking the photo...
*/
#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
if (data == null) {
Toast.makeText(this, "Camera error: data is null!", Toast.LENGTH_LONG).show();
Log.i("PHOTO", "Camera error: data is null!");
// Error is here, data does not contains the uri.
}
else {
Toast.makeText(this, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show();
Log.i("PHOTO", "Image saved to:\n" + data.getData());
}
}
else if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
}
else {
// Image capture failed, advise user
}
}
}
CameraHelper class:
public class CameraHelper {
public static final int MEDIA_TYPE_IMAGE = 1;
/** Create a file Uri for saving an image or video */
public 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()) {
Log.i("PHOTO", "directory is not exists yet!");
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
else {
Log.i("PHOTO", "just made directory: " + mediaStorageDir.getAbsolutePath());
}
}
else {
Log.i("PHOTO", "directory is already exist: " + mediaStorageDir.getAbsolutePath());
}
// 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 {
return null;
}
return mediaFile;
}
}
Log output:
01-13 16:15:37.485: I/PHOTO(6818): directory is already exist: /storage/sdcard0/Pictures/MyCameraApp
01-13 16:15:37.495: I/PHOTO(6818): file uri is: file:///storage/sdcard0/Pictures/MyCameraApp/IMG_20150113_161537.jpg
01-13 16:16:13.482: I/PHOTO(6818): Camera error: data is null!
All the pictures are in the folder: Pictures/MyCameraApp but onActivityResult(...) does not contains the uri in the data field.
What m i doing wrong?
Related
how to implement the flow of both 2 camera APIs(camera and camera2) through interface creation to support older and higher API levels.I implemented android.hardware.Camera in my app and works well for 22 and older APIs but i need to support higher API levels either.I saw this
Android camera android.hardware.Camera deprecated but i do not exactly understand how to implement in my codes an interface which will contain all the 2 cameras' methods like in the link above. my codes are:
private void captureImage() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//Standard Intent action that can be sent to have the camera application capture an image and return it.
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);//Creating file URI to store image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);//The caller may pass an extra EXTRA_OUTPUT to control where this image will be written.
// start the image capture Intent
startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}
/**
* Here we store the file URL as it will be null after returning from camera
* application
*/
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// save file URL in bundle as it will be null on screen orientation
// changes
outState.putParcelable("file_uri", fileUri);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// get the file URL
fileUri = savedInstanceState.getParcelable("file_uri");
}
/**
* Receiving activity result method will be called after closing the camera
* */
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// if the result is capturing Image
if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// successfully captured the image
// display it in image view
previewCapturedImage();
} else if (resultCode == RESULT_CANCELED) {
// user cancelled Image capture
Toast.makeText(getApplicationContext(),
"User cancelled image capture", Toast.LENGTH_SHORT)
.show();
} else {
// failed to capture image
Toast.makeText(getApplicationContext(),
"Sorry! Failed to capture image", Toast.LENGTH_SHORT)
.show();
}
}}
/**
* Display image from a path to ImageView
*/
private void previewCapturedImage() {
try {
imgPreview.setVisibility(View.VISIBLE);
// bitmap factory
BitmapFactory.Options options = new BitmapFactory.Options();
// down sizing image as it throws OutOfMemory Exception for larger images
options.inSampleSize = 8;
final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(), options);
imgPreview.setImageBitmap(bitmap);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
/**
* ------------ Helper Methods ----------------------
* */
/**
* Creating file URI to store image
*/
public Uri getOutputMediaFileUri(int type) {
return Uri.fromFile(getOutputMediaFile(type));
}
/**
* returning image
*/
private static File getOutputMediaFile(int type) {
// External SD card location
File mediaStorageDir = new File (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
IMAGE_DIRECTORY_NAME);
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d(IMAGE_DIRECTORY_NAME, "Oops! Failed create " + IMAGE_DIRECTORY_NAME + " directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date(type));
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else {
return null;
}
return mediaFile;
}
So, I have an app where I want to take a picture, store it to internal storage, and then be able to retrieve it later (presumably via its Uri). Here is what I have thus far:
This code is triggered when my custom camera button is pressed.
cameraButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Intent takePic = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = herp(MEDIA_TYPE_IMAGE);
if (file != null) {
fileUri = getOutputMediaFileUri(file);
Log.d("AddRecipeActivity", fileUri.toString());
takePic.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(takePic, CAMERA_REQUEST);
}
}
});
Next, I've defined two methods later on in the code(mostly taken from the android developer site):
/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(File file){
return Uri.fromFile(file);
}
/** Create a File for saving an image or video */
public File herp(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
Boolean a = false;
String externalDirectory= getFilesDir().getAbsolutePath();
File folder= new File(externalDirectory + "/NewFolder");
// 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 (!folder.exists()){
a = folder.mkdirs();
Log.d("AddRecipeActivity", String.valueOf(a));
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(folder.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else {
return null;
}
if(mediaFile == null){
Log.d("AddRecipeActivity", "Media file is null");
}
return mediaFile;
}
When I print my Uri (right before triggering the intent) I get the following output.
04-04 04:22:40.757 22402-22402/scissorkick.com.project2 D/AddRecipeActivity: file:///data/user/0/scissorkick.com.project2/files/NewFolder/IMG_20160404_042240.jpg
Also, when I check if the directory is made, the boolean is true.
When my camera intent's onActivityResult is run, however, the result code is 0.
Why might it fail at this point? I've defined the appropriate permissions in the manifest, and also request external storage write permissions during run time.
Edit: Added the onActivityResult:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == CAMERA_REQUEST){
Log.d("AddRecipe", String.valueOf(resultCode));
if(resultCode == RESULT_OK){
photo = (Bitmap) data.getExtras().get("data");
thumb = ThumbnailUtils.extractThumbnail(photo, 240, 240);
photoView.setImageBitmap(thumb);
//Toast.makeText(getApplicationContext(), "image saved to:\n" + data.getData(), Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(getApplicationContext(), "Fail", Toast.LENGTH_SHORT).show();
}
}
}
There's some nonsense code in the onActivityResult, but the point is that the resultCode = 0 and I don't know why.
In your final activity, put the below code
data.putExtra("uri", uri);//uri = your image uri
getActivity().setResult(""result_code", data);
getActivity().finish();
Then in your onActivityResult code you can get the uri like
Uri uri = data.getExtras().getParcelable("uri");
Then you can use this Uri value to retrieve your image.
There is how i take picture in my app!
When i press my own Image Button
static final int REQUEST_IMAGE_CAPTURE = 1;
static final int REQUEST_TAKE_PHOTO = 1
static final String STATE_PHOTO_PATH = "photoPath";
ImageButton photoButton = (ImageButton) this.findViewById(R.id.take_picture_button);
photoButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dispatchTakePictureIntent();
}
});
And here how manage and create/store the file with image
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
//Create a new empty file for the photo, and with intent call the camera
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException e) {
// Error occurred while creating the File
Log.e("Error creating File", String.valueOf(e.getMessage()));
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
//I have the file so now call the Camera
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
private void openImageReader(String imagePath) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri imgUri = Uri.parse(imagePath);
intent.setDataAndType(imgUri, "image/*");
startActivity(intent);
}
In the ActivityResult i only save a record in DB, with the Path of the image so i can retrieve it back and read the photo stored like file.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
//Save the path of image in the DB
db.addCompito(new Compiti(activity_name, null, mCurrentPhotoPath));
refreshListView();
}
}
If you have some screen rotation don't forget to add something like
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putString(STATE_PHOTO_PATH, mCurrentPhotoPath);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentPhotoPath = savedInstanceState.getString(STATE_PHOTO_PATH);
}
WHY?
Because when the rotation change you can lose the file that you have created for the "new photo" and when you accept it and save it, your photopath is null and no image is created.
I am making a camera app and I wanted to save the photos taken into the internal storage. I wish to make all the photos taken accessible to the user, not only for my app. I think I should not use the File class by android. Any suggestion?
In your onClick call capturePicture(): and copy paste below code
private void capturePicture()
{
if (isCameraPresent())
{
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = Uri.fromFile(getOutputMediaFile());
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(intent, Global.CAMERA_CAPTURE_REQUEST_CODE);
}
}
private File getOutputMediaFile()
{
// External sdcard location
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
Global.IMAGE_DIRECTORY_NAME);
// Global.IMAGE_DIRECTORY_NAME is String in Global value is abc/images
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists())
{
if (!mediaStorageDir.mkdirs())
{
Log.d(Global.IMAGE_DIRECTORY_NAME, "Oops! Failed create " + Global.IMAGE_DIRECTORY_NAME + " directory");
return null;
}
}
File mediaFile = new File(mediaStorageDir.getPath() + File.separator + "CAPTURE" + ".jpg");
return mediaFile;
}
private boolean isCameraPresent()
{
if (getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))
return true;// this device has a camera
else
return false;// no camera on this device
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == Global.CAMERA_CAPTURE_REQUEST_CODE)
{
if (resultCode == RESULT_OK)
{
// Image is saved into internal pictures folder >> abc folder>>Images
}
else
{
// failed to capture image
Toast.makeText(getApplicationContext(), "Sorry! Failed to capture image", Toast.LENGTH_SHORT).show();
}
}
}
This will save captured image in internal storage/Pictures/abc/images
Hope this is what you want and this helps you :)
I'm having trouble with my camera app. I'm trying to make it snap a picture and then save it to a folder of the android device and it seems to be doing that, but the pictures only show up after I reboot the device. Furthermore, I seem to always end up with the result code of 0, so I never get to update my imageView. Why do I always get that result code?
/** Create a file Uri for saving an image */
private static Uri getOutputMediaFileUri(){
return Uri.fromFile(getOutputMediaFile());
}
/** Create a File for saving an image */
private static File getOutputMediaFile(){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "myAppPics");
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("myAppPics", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
return mediaFile;
}
/** Opening App*/
public void open(){
intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
fileUri = getOutputMediaFileUri(); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
startActivityForResult(intent, 0);
}
#Override
/**when you get the activity result*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
//if you want to keep the picture
if (resultCode == RESULT_OK )
{
//grab image data
Bundle extras = data.getExtras();
Bitmap bp = (Bitmap) extras.get("data");
//make imageView hold that image now
myImgV.setImageBitmap(bp);
Log.d("MyCameraApp", "update image");
}
//else just goes back to previously chosen image
else
Log.d("MyCameraApp", "don't want to update image "+resultCode);
}
To see the picture taken refresh the gallery using
refreshGallery(String fileUrl, Context ctx) {
Intent mediaScanIntent = new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(fileUrl);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
ctx.sendBroadcast(mediaScanIntent);
}
I need to record a video within the application using the intent. I think the code is correct, however when I do start the image stops and the file gets 0Bytes. I let down the code I'm using.
The first function called:
protected void makeVideo() {
//create new Intent
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO); // create a file to save the video
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // set the video image quality to high
// start the Video Capture Intent
startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
}
getOutputMediaFile function:
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
// Environment.getExternalStorageState();
// File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), Constants.ALBUM.AlbumInPhone);
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), Constants.ALBUM.AlbumInPhone);
// 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(Constants.ALBUM.AlbumInPhone, "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;
}
File x = mediaFile;
int y=0;
y=1;
return mediaFile;
}
private static Uri getOutputMediaFileUri(int type){
return Uri.fromFile(getOutputMediaFile(type));
}
and:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
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();
String uri = fileUri.getPath();
if(TextUtils.isEmpty(uri)){
Log.v(TAG, "Could not get video");
} else {
Log.v(TAG, "video: " + uri);
if(BebeDataBaseManager.addVideoToAlbum(this, uri, albumId)){
Log.v(TAG, "video: added");
this.cursor.requery();
} else {
Log.v(TAG, "video: not added");
}
}
} else if (resultCode == RESULT_CANCELED) {
// User cancelled the video capture
} else {
// Video capture failed, advise user
}
}
...
I'm doing something wrong?