I am developing a custom camera app in Android. My goal is to save a picture to file and open it in the fullscreen mode as soon as the file has been saved. Unfortuantely, the problem is that my main activity (ImageCapture) doesn't wait for ImageCaptureCallback results before calling the next activity (ImageDisplay).
To take a picture I am using a custom ImageCaptureCallback, which saves captured image to "tmpPicturePath" using OutputStream. Later the ImageDisplay activity is called - it reads the file saved in tmpPicturePath.
camera.takePicture(mShutterCallback, mPictureCallbackRaw, new ImageCaptureCallback(this));
// ImageCaptureCallback saves the file in tmpPicturePath
Intent intent = new Intent(ImageCapture.this, ImageDisplay.class);
intent.putExtra("tmpPicturePath", this.getTmpPicturePath());
startActivity(intent);
BUT the file that should be created in ImageCaptureCallback is not yet available at the moment of calling ImageDisplay activity. The overall effect is that not the actual but the previously taken picture is available in the ImageDisplay class. Do you have an idea how to handle this issue? In other words how to wait for callback results before calling the next activity?
Many thanks!
Sample code for taking picture from camera
void selectPhoto() {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "New Picture");
values.put(MediaStore.Images.Media.DESCRIPTION, "From your Camera");
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, SELECT_PHOTO);
}
and in onActivityResult() method
try {
imageBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Related
I'm currently trying to save images taken from a phone to its gallery, but the code below only works if I choose the stock camera app when the chooser dialog pops up. Whenever I choose another camera app(e.g., the Google camera), the taken picture doesn't get saved any where.
To make things even stranger, sometimes the picture does show up in its designated directory in the gallery, but after 15 mins or so, the same goes for when I use the stock camera app: the picture will get saved in the default camera shots directory, but takes quite a bit to show up in its designated directory, if it shows up there at all.
// Capturing Camera Image will launch camera app request image capture
void captureImage() {
//file uri to store image.
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
// Request camera app to capture image
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start the image capture Intent
getActivity().startActivityForResult(captureIntent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}
well ,
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
does not work anymore .
you should do something like this :
call Camera Activity :
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
and onActivityResult :
if (data.getData() == null) {
Bitmap bm = (Bitmap)
data.getExtras().get("data");
String timeStamp = new SimpleDateFormat(
"yyyyMMdd_HHmmss").format(new Date());
File pictureFile = new File(Environment
.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES)
.getAbsolutePath()
+ File.separator + "IMG_" + timeStamp);
try {
FileOutputStream fos = new FileOutputStream(
pictureFile);
bm.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.close();
String filePath = pictureFile.getAbsolutePath();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} } else {
Uri imgUri =data.getData());
}
It turns out my code was working after all. The pictures were being saved in the new directory, but the problem was that the gallery wasn't being updated, which explains why the photos would randomly appear in the directory later on. Being new to this, it never occurred to me that I would have to update the gallery. I only came to this realization after using ES File Explorer to look through my files. To fix my problem, I just made a new method in my CameraFragment that would call on the media scanner. I called this method from onActivityResult().
Here's the new method, though there's nothing really "new" about it since I ran into the same code on other SO questions:
protected void mediaScan() {
getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.parse(fileUri.toString())));
}
I also don't need to call the package manager and iterate through the apps that could handle the camera intent if I'm not giving the option to use choose a picture from a gallery, so I'm going to remove all that from my question.
I'm writing an application with one of the key features being taking a photo and writing it to a file, then reading that photo into a base64 array (all in the one button click). The problem being that when i initiate the onclick to take a photo it will return from this function before the onPhotoTaken() function has received the image and written it to the storage directory specified.
I have added log outputs at several stages in the code and it is clear that the onclick takePhoto function is exiting before the onPhotoTaken() function that it calls is finished.
The android documentation states that you need to wait for JpegCallback to finish returning before you can restart the preview but I am having trouble getting it to wait for the write to finish.
code:
public static void takePhoto(){
fCamera.takePicture(null, null, jpegCallback);
Log.d("capture", "photo was captured");
// Set the image callback
Log.d("this one is", "being called");
}
static PictureCallback jpegCallback = new Camera.PictureCallback() {
// Function for handling the picture
public void onPictureTaken(byte[] data, Camera fCamera){
//fCamera.stopPreview();
Log.d("is this", "not being called ??? probably");
File imagePath;
FileOutputStream out = null;
// create the filename with extension
String fileName = "IMAGE_1.bmp";
// Create / Find the storage Directory for our pictures
//storageDir = context.getDir("imageDir", Context.MODE_PRIVATE);
// Create it if it doesn't exist
// Create the image file
imagePath = new File(storageDir, fileName);
String finalPath = imagePath.getAbsolutePath();
Log.d("location", finalPath);
if (!imagePath.exists()) {
if (!imagePath.mkdirs())
Log.d("#string/app_name", "Failed to create File");
return;
}
try {
out = new FileOutputStream(imagePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//finalImage.compress(CompressFormat.PNG, 100, out);
try {
out.write(data);
Log.d("write", "photo was written");
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
};
Log cat:
10-13 12:55:39.185: D/capture(7126): photo was captured
10-13 12:55:39.185: D/this one is(7126): being called
These are the only log outputs that occur.
I have the same problem, by taking a photo and then try to create a thumbnail and store it to the media gallery.
As it's defined in here(developer.android.com/reference/android/hardware/Camera.html#takePicture) takePicture is an asynchronous proccess, so you have to derive your program logic and mandate the sequence.
This can be implemented with AsyncTask (http://developer.android.com/reference/android/os/AsyncTask.html)
In this example, the code inside onPostExecute method will be executed after camera.takePicture (so you are sure that onPictureTaken from PictureCallback is done).
I have a Problem. I start from my own Application the Build-In Photoapplication with a Photo-Intent.
String photoName = System.currentTimeMillis() + ".jpg";
File file = new File(getFilesDir(),//Environment.getExternalStoragePublicDirectory(
//Environment.DIRECTORY_DCIM),
photoName); // Anlegen der Datei im entsprechenden
// Verzeichnis
FileOutputStream fos = null;
try {
fos = openFileOutput(photoName, Context.MODE_WORLD_WRITEABLE);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
outputFileUri = Uri.fromFile(file);
intentPhoto.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
//startActivity(intentPhoto);
startActivityForResult(intentPhoto, TAKE_PICTURE);
This is my Code to start the Activity. As you can see, the first thing i do is to set up the file in the directory and then give the intent the location of the file to store it.
But everytime i take a picture it is not saved to the Pictures Directory. The only way to save the picture is to turn off the phone and restart it. Then every picture I have taken befor is there. This happens since the last updated to 4.1.1. Befor i updated the phone, everything worked fine, but since the update I have this problem.
Can somebody help me? Does anyone have the same Issue?
Make sure you offer the new file to be scanned:
MediaScannerConnection.scanFile(this,
new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
// code to execute when scanning is complete
}
});
You can pass in a null argument for the OnScanCompletedListener if you don't need to be notified when the scanner has picked it up, but you might want to at least put a logging statement there.
It works fine now, the problem was that I create the File by my self, with:
File file = new File(..);
But you have to use:
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "IMG_"+ timeStamp+.jpg");
And put it into the intent to save the file at once without restarting the phone.
I'm new to android. Now, i'm doing image capturing function using:
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE );
The problem is after I capture my photo, the new captured photo does not display on the image display page.
Does anyone here know where there is code that can help me refresh my android or any step that I need to do so that my image display page can be updated once I capture a new photo?
Any help would be very appreciated and many thanks to you first.
Updated answer:
I use this, may be this can help others:
mScanner = new MediaScannerConnection(
Camera.this,
new MediaScannerConnection.MediaScannerConnectionClient() {
public void onMediaScannerConnected() {
mScanner.scanFile(outputFileUri.getPath(), null /* mimeType */);
}
public void onScanCompleted(String path, Uri uri) {
//we can use the uri, to get the newly added image, but it will return path to full sized image
//e.g. content://media/external/images/media/7
//we can also update this path by replacing media by thumbnail to get the thumbnail
//because thumbnail path would be like content://media/external/images/thumbnail/7
//But the thumbnail is created after some delay by Android OS
//So you may not get the thumbnail. This is why I started new UI thread
//and it'll only run after the current thread completed.
if (path.equals(outputFileUri.getPath())) {
mScanner.disconnect();
//we need to create new UI thread because, we can't update our mail thread from here
//Both the thread will run one by one, see documentation of android
Camera.this
.runOnUiThread(new Runnable() {
public void run() {
}
});
}
}
});
mScanner.connect();
Sally, did you mean that after you take a photo you don't see it in the gallery or file-manager when you look at the directory you know the file to be in?
If so, you need to run the media-scanner like this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
... where uri is the uri of the photo, since you know it already, although you can use the uri of the directory instead if that's easier (though it is slower - potentially very slow if the directory contains many files or nested directories).
you should take photo using below code::
Calendar cal = Calendar.getInstance();
File file = new File(Environment.getExternalStorageDirectory(),(cal.getTimeInMillis()+".jpg"));
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
selectedImageUri = Uri.fromFile(file);
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, selectedImageUri);
startActivityForResult(i, CAMERA_RESULT);
and on activity result you can use these code:::
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CAMERA_RESULT:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), selectedImageUri);
imageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
You can refresh your activity with :
Intent myIntent = getIntent();
finish();
startActivity(myIntent);
So far I have my app taking a picture creating a new folder on the SD Card and saving the pictuers into the new folder.
I'm trying to get it so once the picture has been took it will display in a new Activity with two buttons that say "Use" or "Retake". So far the image saving is working perfectly fine but once the image has been took and it tries to open the new Activity it just stays on the camera Activity and shows the image which I cant use as it has a surfaceView onit.
In my LogCat I get the error "Oh, no reference" which is set to show if it can't find the picture, which is why im thinking it may be because I am not calling the picture from the correct place in my Punch.java.
So basiclly I am trying to once an image has been took the app to open a New Activity "Punch.java" and display the image that has just been took.
UPDATE Thanks to Lumis (code below has been updated)
Changed
intent.putExtra("filepath",uriSavedImage);
to
intent.putExtra("filepath",uriSavedImage.toString());
Which now opens the new Activity but still cannot see the image.
UPDATE 2 Punch.java
I have updated my Punch.java as with the new code if i change (myRef) to "/sdcard/Punch/image_0.jpg" I can see that image but I need it to referance to the image that was just taken with the camera which is something to do with this line I think intent.putExtra("filepath",uriSavedImage.toString());
Update 3
Nearly working perfectly now using intent.putExtra("filepath",Uri.parse(output.getAbsolutePath()).toString()); but for some reason it is still putting mnt/sdcard at the start it just needs to be sdcard/
Ok now working fine /mnt/sdcard is when the sdcard was mounted to the computer while i took the picture.
In my Camera Activity I have
PictureCallback myPictureCallback_JPG = new PictureCallback(){
public void onPictureTaken(byte[] arg0, Camera arg1) {
// TODO Auto-generated method stub
/*Bitmap bitmapPicture
= BitmapFactory.decodeByteArray(arg0, 0, arg0.length); */
int imageNum = 0;
Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File imagesFolder = new File(Environment.getExternalStorageDirectory(), "Punch");
imagesFolder.mkdirs(); // <----
String fileName = "image_" + String.valueOf(imageNum) + ".jpg";
File output = new File(imagesFolder, fileName);
while (output.exists()){
imageNum++;
fileName = "image_" + String.valueOf(imageNum) + ".jpg";
output = new File(imagesFolder, fileName);
}
Uri uriSavedImage = Uri.fromFile(output);
imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage);
OutputStream imageFileOS;
try {
imageFileOS = getContentResolver().openOutputStream(uriSavedImage);
imageFileOS.write(arg0);
imageFileOS.flush();
imageFileOS.close();
Toast.makeText(AndroidCamera.this,
"Image saved",
Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Intent intent = new Intent(getBaseContext(), Punch.class);
intent.putExtra("filepath",uriSavedImage.toString());
//just using a request code of zero
int request=0;
startActivityForResult(intent,request);
}};
And my Punch.java which is the next Activity is:
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.punch);
String myRef = this.getIntent().getStringExtra("filepath");
File imgFile = new File(myRef);
if(imgFile.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
ImageView myImage = (ImageView) findViewById(R.id.imagepunch);
myImage.setImageBitmap(myBitmap);
}
}
}
I think it is the file path issue. You submitted your file path as URI but you are reading it in the viewer activity as a string.
Perhaps you neet to change this line into:
intent.putExtra("filepath",uriSavedImage.toString());
Or
intent.putExtra("filepath",Uri.parse(output.getAbsolutePath()).toString());
Different version of android may not work the same when it comes to file path, so you need to experiment using Uri.parse(fileStr) or String...
Just looking at your code and your approach, I think what you would typically see in this scenario is a new content handler registered so that it appears under the "Share" option of the camera / image library. This way, you are not getting involved in the use/retake logic which is essentially redundant for built-in Android functionality. Think of an app like Evernote or Picasa. You take a picture (or look one up that you took previously) and select "Share". One of the Share options, along with Picasa, Email, etc would be your app. That is how I would do it.