I am trying to take photo using IMAGE_CAPTURE intent and show this photo on the screen immediately. What I do:
File photoFile = createImageFile();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(intent, REQUEST_CAMERA);
Create image file method:
private File createImageFile() {
File dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File photoFile = null;
try {
photoFile = File.createTempFile("photo", ".jpg", dir);
mPhotoPath = photoFile.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
return photoFile;
}
When onActivityResult is called I execute:
Bitmap photo = BitmapFactory.decodeFile(mPhotoPath);
mPhoto.setImageBitmap(photo);
Here is a problem. Apparently IMAGE_CAPTURE activity saves image to a file in background and my onActivityResult gets executed before image is saved. Because of this my photo == null. Although it works if I put breakpoint before BitmapFactory.decodeFile call. I fixed it with an ugly hack:
while (photo == null) {
photo = BitmapFactory.decodeFile(mPhotoPath);
}
So, am I doing something wrong? Why it works this way?
I am testing on Marshmallow Nexus 5.
Apparently IMAGE_CAPTURE activity saves image to a file in background and my onActivityResult gets executed before image is saved
I would consider that to be a bug in the specific camera app that is handling your request. There are hundreds, if not thousands, of such camera apps, and bugs like this are somewhat common.
I fixed it with an ugly hack
Busy loops like that are never a good idea. Among other things, it will freeze your UI if done in the main application thread, and it will seriously chew up CPU even if done on a background thread.
I would try a FileObserver to watch for when the file is closed, to be more event-driven. If, for whatever reason, you can't get that to work:
make sure you are doing your watch-for-the-file logic in a background thread
add reasonable SystemClock.sleep() periods between tries (e.g., 50ms)
Related
I'm strugglin with this already all day :-( My current approach looks like this
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/image.jpg");
imagePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/image.jpg";
startActivityForResult(IntentUtils.dispatchTakePictureIntent(getActivity(), file), REQUEST_IMAGE_CAPTURE);
afterwards i do some unimportant stuff to make display the Bitmap correctly and then display it with this method
placeImageView.setImageBitmap(rotatedBitmap);
*EDIT This is how i create the Intent
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) {
if (file != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(file));
return takePictureIntent;
}
}
return null;
}
This works so far.
But when i use this imagePath in the next activity, the bitmap won't load. I already tried before so many things with this file path before, at the moment i just feel owerwhelmed by all the possible ways to handle this ...
This may sound trivial, but you have checked if the image really gets recorded where you want it to be - i.e. have you checked for the image by using the standard phone file explorer? (I would have posted this as a comment, but my reputation is too low.)
I have been trying everything to start an Activity for Result but keeping the caller activity seems impossible.
I Have tried setting on the caller activity in the manifest "android:onConfigChanges" for screenSize, orientation and keyboardHidden.
It is very important because in the caller Activity an Asyn Task loads the content from a Web Service.
When the Activity gets resumed after taking the picture, the Caller activity gets destroyed and loads again the entire UI from the Web Service and destroy the user imputs. Is there a way to prevent this?
This is the Caller method for the camera intent.
private void openCamera(){
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
//takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); <- Commented and not commented with the same problem.
// Create the File where the photo should go
try {
photoFile = createImageFile();
} catch (IOException ex) {
ex.printStackTrace();
}
// Continue only if the File was successfully created
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
An this is the "createImageFile()":
private File createImageFile() throws IOException {
// Create an image file name
File file;
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = timeStamp + "_";
File storageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "myAppDirectory");
if (!storageDir.mkdir()){
storageDir.mkdirs();
};
file = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
mCurrentPhotoPath = file.getAbsolutePath();
return file;
}
I have been trying everything to start an Activity for Result but keeping the caller activity seems impossible.
Most likely, your process is being terminated due to low memory conditions. This is fairly typical when using ACTION_IMAGE_CAPTURE or other actions that launch a third-party camera app. It also happens in many other places as well, as your app's process will not live forever.
It is very important because in the caller Activity an Asyn Task loads the content from a Web Service.
Please bear in mind that there are plenty of other cases when your process will be terminated, and you need to be able to deal with this. So, if your concern is re-doing the Web service call, cache the results of the previous call in a file, and only re-issue the call if your cached results are stale. You might also consider whether your activity should be doing this Web service call at all, moving that logic instead into an IntentService.
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 do not know how to open saved image and display it into gridView.
I make an intent to take a photo:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null && file != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
And file is saved in /data/data/package/files/...
But when I tried to open file and create a bitmap it always return null.
try {
is = this.getContentResolver().openInputStream(Uri.fromFile(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(is);}
even if I use decodeFile method() I still have a null bitmap.
Files exist in data/data/ ... I checked it.
My question is: how can I get dispaly taken image?
Actually you can't store Pictures caught on camera directly on your app memory, you should write it to sdcard and copy it to your space and delete the original. Because camera is a another app that has no privillege to write on your apps storage space. You can check that if you have root permissions.
If you specify your app memory for camera intent it will always return NULL
You can read this for WORLD_WRITEABLE
I noticed very strange behaviour of my device.
I create a new intent with action MediaStore.ACTION_IMAGE_CAPTURE
Then I start an activty for result. But at the moment I take a picture from the camera my application disappears from processes in DDMS perspective. Then in few seconds it is running again.
What is interesting - onActivityResult is called properly and receives an image. But I have some singletones that contain some values in their fields. After process is restarted these singletones are re-initialized and lose all values.
There is no problem on other devices - neither tablets nor phones.
Is it a known bug? Ho to prevent process restarting on Galaxy Tab 2 10.1?
Thanks in advance!
UPDATE: Below is my code that starts camera intent
private void startCameraIntent() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
File albumFile;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO){
albumFile = new File (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), FOLDER_NAME);
} else {
albumFile = new File(Environment.getExternalStorageDirectory()+CAMERA_DIR+FOLDER_NAME);
}
if (albumFile != null){
if (!albumFile.mkdirs()){
if (!albumFile.exists()){
showToast(getApplicationContext().getString(R.string.sFailedToCreateDirectory));
return;
}
}
}
File imageFile = null;
try {
imageFile = File.createTempFile(imageFileName, JPEG_FILE_SUFFIX, albumFile);
mCurrentPhotoPath = imageFile.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile));
fileUri = Uri.parse(mCurrentPhotoPath);
startActivityForResult(cameraIntent, ACTION_CAPTURE_IMAGE);
} else {
showToast(getApplicationContext().getString(R.string.sSDNotReady));
}
}
Is it a known bug?
It is not a bug. If your app is not in the foreground, its process can be terminated at any time.
Ho to prevent process restarting on Galaxy Tab 2 10.1?
You can't. Your process can go away at any time when it is not in the foreground. So, for example, if the user presses HOME, and later Android terminates your process, and after that the user tries returning to your app via the recent-tasks list, you will see the same behavior. Your app needs to be able to handle this.
You are welcome to try working with the Camera directly, rather than starting the third-party activity, as that will keep your app in the foreground. This is more complex than what you are doing, though.