After reading this documentation https://developer.android.com/training/camera/photobasics I want to take a photo and to store the uri of the photo into a given variable. The problem is that I'm storing the variable name and the uri into the intent with takePictureIntent.putExtra(Constants.INTENT_EXTRA_VARNAME, variable) and takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI), but in onActivityResult the intent data is empty, and neither the variable and the uri stored are empty. I need to know the uri and the variable. What am I doing wrong?
I need to pass the information as intent data because the class which is firing the action of displaying the camera is differente from the activity class.
class with the action:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(Constants.INTENT_EXTRA_VARNAME, variable);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(SectionManager.getInstance().getCurrentActivity().getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
ex.printStackTrace();
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(SectionManager.getInstance().getCurrentActivity(), SectionManager.getInstance().getCurrentActivity().getPackageName(), photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
SectionManager.getInstance().getCurrentActivity().startActivityForResult(takePictureIntent, Constants.REQUEST_IMAGE_CAPTURE);
}
}
my activity which receives the result:
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if( requestCode == Constants.REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK){
String varName;
String path;
if(intent != null) {
varName = intent.getStringExtra(Constants.INTENT_EXTRA_VARNAME);
path = Util.getRealPathFromURI(SectionManager.getInstance().getCurrentActivity(), intent.getData());
Log.d(DEBUG_TAG, "onActivityResult-> varName: "+varName+" path: "+path);
if (varName != null && path != null) {
VariableManager.put(varName, path);
}
}
}
}
manifest, permission write_external_storage and this code:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
file_paths.xml file:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="/" />
</paths>
You already have photoURI which you send with MediaStore.EXTRA_OUTPUT so You can simply use it . Save photoURI as globally and directly use it . See if RESULT_OK is emitted then it means picture was clicked and it will be saved at the EXTRA_OUTPUT location.
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if( requestCode == Constants.REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK){
// USe photoURi here
}
}
You can not expect some custom key which is Constants.INTENT_EXTRA_VARNAME will be return with System camera Intent. I do not have any knowledge of such thing.
If you specified MediaStore.EXTRA_OUTPUT the image taken will be written to that path, and no data will given to onActivityResult so you need to persist the file path.
PS : You can save it globally and also make sure you should persist it during onSaveInstanceState().
Related
I used similar code in different apps but still this time I am getting a problem. upon calling startActivityForResult(CamIntent, Integer.parseInt(code)); camera open but when I click image nothing happens it keeps clicking the image but does not show image page with tick and cross icons.
In Manifest File
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
#xml/file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." />
</paths>
Code in Activity
public void ClickImageFromCamera(String code) {
Intent CamIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File destination = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
Log.e("img fromCam", String.valueOf(destination));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(Objects.requireNonNull(getApplicationContext()),
BuildConfig.APPLICATION_ID + ".fileprovider", destination);
Log.e("img uri", String.valueOf(uri));
CamIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
} else {
uri = Uri.fromFile(destination);
CamIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
}
CamIntent.putExtra("return-data", true);
startActivityForResult(CamIntent, Integer.parseInt(code));
}
Log
D/CompatibilityChangeReporter: Compat change id reported: 147798919; UID 10625; state: DISABLED
D/OpenGLRenderer: endAllActiveAnimators on 0x76e3d22fc0 (AlertController$RecycleListView) with handle 0x7603cc4890
E/img fromCam: /storage/emulated/0/1611230389449.jpg
E/img uri: content://com.example.aps.fileprovider/external_files/1611230389449.jpg
E/Request code: 0 (when I click back)
E/ResultCode: 0
private void openCameraImagePickerIntent() {
int FRONT_CAMERA = 0;
int BACK_CAMERA = 1;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra("android.intent.extras.CAMERA_FACING",BACK_CAMERA);
startActivityForResult(intent, 14596);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 14596 && resultCode == RESULT_OK) {
Bitmap imageBitmap = (Bitmap) data.getExtras().get("data");
//Save imageBitmap in storage
}
}
My API Version is 24
I'm using Camera and Bluetooth. And my device communicating other device.
The first function is, I'm going to call up the camera app from my app, take a picture and send it to other device.
The second function is, I want to import the file I want to send and send it to another device through Bluetooth.
These two can be run on different projects, but two cannot be executed within one project.
this is my error "Caused by: android.os.FileUriExposedException: file:///sdcard/Download/example.txt exposed beyond app through ClipData.Item.getUri()"
I'll put a piece of the code up.
CameraActivity.class
private void sendTakePhotoIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
if (photoFile != null) {
photoUri = FileProvider.getUriForFile(this, getPackageName(), photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
Bluetooth.class
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == DISCOVER_DURATION && requestCode == REQUEST_BLU) {
Intent i = new Intent();
i.setAction(Intent.ACTION_SEND);
i.setType("*/*");
File file = new File(exist);
i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(i, 0);
if (list.size() > 0) {
String packageName = null;
String className = null;
boolean found = false;
for (ResolveInfo info : list) {
packageName = info.activityInfo.packageName;
if (packageName.equals("com.android.bluetooth")) {
className = info.activityInfo.name;
found = true;
break;
}
}
if (!found) {
Toast.makeText(this, "Bluetooth not been found", Toast.LENGTH_LONG).show();
} else {
i.setClassName(packageName, className);
startActivity(i);
}
}
} else {
Toast.makeText(this, "Bluetooth is cancelled", Toast.LENGTH_LONG).show();
}
}
Manifests.xml - provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.tech.www.communicatever_110"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
res/xml/file_paths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.tech.www.communicatever_110/files/Pictures" />
If you need any more code, please request it.
I know this answer is quite late but let's hope it helps someone in future.
First of all in your CameraActivity.class you need to concatenate ".providers" with your package name (it should look like this)
photoUri = FileProvider.getUriForFile(this, getPackageName() + ".providers", photoFile);
And you'll have to do the same inside Manifest.xml (add .providers with your package name)
android:authorities="com.tech.www.communicatever_110.providers"
Thirdly, inside res/xml/file_paths.xml you can use name="my_images" only if you're using Context.getFilesDir() (i.e. scoped storage) but if you're using Environment.getExternalStorageDirectory() then you must use name="external_files".
Last but not least, you might not need to put the whole path inside file_paths.xml
path="Android/data/com.tech.www.communicatever_110/files/Pictures"
Try replacing it with: path="."
I am using an implicit Intent to take a picture. I have been following the work outlined in this tutorial. The issue that I am having is that the extra added to the Intent is not being delivered. Here is the code I'm using:
private void dispatchTakePictureIntent(Context context) {
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) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile(this.getActivity());
} catch (IOException ex) {
Log.e(TAG, "Error creating file: " + ex.toString());
//TODO: 2017/1/24 - Handle file not created
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Error")
.setMessage(ex.toString());
final AlertDialog dialog = builder.create();
dialog.show();
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(context,
"com.example.myapp",
photoFile);
//THIS EXTRA IS NOT BEING ADDED TO THE INTENT
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
galleryAddPic(context, photoFile.getAbsolutePath());
}
}
}
When the onActivityResult method is fired, the Intent is empty. Here is that code:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
//These extras are empty. I have used the debug tool, and there is nothing in here.
Bundle extras = data.getExtras();
//extras is null
imageBitmap = (Bitmap) extras.get("data");
previewImage.setImageBitmap(imageBitmap);
}
}
Why is the intent empty? What do I need to do to fix this issue?
Why is the intent empty?
Because you asked for it to be empty, by including EXTRA_OUTPUT in your ACTION_IMAGE_CAPTURE request. Quoting the documentation:
The caller may pass an extra EXTRA_OUTPUT to control where this image will be written. If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap object in the extra field. This is useful for applications that only need a small image. If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri value of EXTRA_OUTPUT.
What do I need to do to fix this issue?
Either:
Get rid of EXTRA_OUTPUT (if you want a thumbnail-sized image), or
Stop looking for the "data" extra, and look in the location that you specified in EXTRA_OUTPUT
I am using code from http://developer.android.com/training/camera/photobasics.html
Code:
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = FileUtilities.createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
Toast.makeText(getActivity(),"Error!",Toast.LENGTH_SHORT).show();
}
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
Bundle extras = data.getExtras(); //error
//code after this doesn't get executed
}
}
I'm trying to get access to the thumbnail and the picture being stored on the device. But for some reason when I try the code, I get a null pointer exception on the data.getExtras(); part.
What am I missing here?
That's one of notorious Android development experience.
Android Intent does not guarantee to give captured image in data.getExtras(), especially user utilize 3rd party camera/imaging app. You can find many trials and suggestions in here and anywhere googled with "android camera intent null".
Some common of them are as below.
data.getExtras().get("data");
data.getExtras() with different key (i.e "photo")
data.getData()
Uri.fromFile(f) for EXTRA_OUTPUT predefined path.
Uri.fromFile(f) with some random filename (datetime format or IMG-xxx) without maintaining EXTRA_OUTPUT definition.
I recommend you to find it using breakpoint which route of the variable that the intent given. It would be good to check all of them in if-else if-else approach.
In addition, check out crash report carefully after releasing the app. You may get the error out of the above trials.
To get the ThumbNail, you don't need to create a file etc. please try this code below.
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
and to get the results.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
imgView.setImageBitmap(imageBitmap);
}
}
imgView is the ImageView you want to set the ThumbNail to.
In case if you want to create a file and then try this, [ which is not needed for a Thumbnail], you may want to try adding the following permission to manifest as you are trying to read and write to storage.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
All the best.
I am trying to test the sample code related to capturing an image via camera. The documentation says that a URI can be passed as an extra in the intent were the camera will save the image.
I tried the following :
// image1 doesn't exist
File file = new File(getFilesDir() + "/image1");
Uri uri = Uri.fromFile(file);
Intent i = new Intent();
i.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, uri);
if (i.resolveActivity(getPackageManager()) != null) {
startActivityForResult(i, 1337);
}
I am trying to place the image as a file named image1 in my files directory. I am testing this on the genymotion VM. I have tested getting the image as a bitmap in the return Intent, but when I use the above approach, the camera app gets stuck when I click done after taking the picture.
I'm guessing it has something to do with URI permissions. Do I need to add some permissions in the intent like in data sharing ?
Edit:
I tried to follow these instructions, except I want to save the photo in my app's directory, so I tried the following but it doesn't work (the app has camera permission) :
String imagePath = null;
try {
File image = File.createTempFile("testImage", ".jpg", getFilesDir());
imagePath = "file://" + image.getAbsolutePath();
}
catch(Exception e){
Toast.makeText(getApplicationContext(), "" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
File file = new File(imagePath);
Uri uri = Uri.fromFile(file);
Intent i = new Intent();
i.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, uri);
if (i.resolveActivity(getPackageManager()) != null) {
startActivityForResult(i, 1337);
}
I also have onActivityResult(), but its no use, as the camera app gets stuck as explained above.
Also, an additional question : When I don't have camera permission in my test app, I can still invoke the camera and the get the bitmap in intent extra, how so ? Is this something specific to genymotion VM ?
Make sure you have these permissions for your manifest
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
Everything looks good to me. Do you have onActivityResult()
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == RESULT_OK){
String result=data.getStringExtra("result");
}
if (resultCode == RESULT_CANCELED) {
//Write your code if there's no result
}
}
}//onActivityResult