I have implemented device camera functionality in my Android app. It's working well and good in all devices I've tested it out. Now I received a crash report from a user who is using Pixel XL.
Is there any change in Pixel XL for fetching the bitmap from onActivityResult?
My code:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == AppConstants.ACTION_REQUEST_CAMERA && resultCode == Activity.RESULT_OK) {
if(data != null) {
if(data.getData()!=null) {
try {
if (bitmap != null) {
bitmap.recycle();
}
InputStream stream = getContentResolver().openInputStream(data.getData());
bitmap = BitmapFactory.decodeStream(stream);
stream.close();
setCircularBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
bitmap = (Bitmap) data.getExtras().get("data");
setCircularBitmap(bitmap);
}
} else {
LogUtils.debug("path",initialURI.getEncodedPath());
bitmap = getBitmapFromUri(initialURI);
setCircularBitmap(bitmap);
Toast.makeText(EditProfileActivity.this, "path " + initialURI.getEncodedPath(), Toast.LENGTH_SHORT).show();
}
isProfileImageUpdated = true;
super.onActivityResult(requestCode, resultCode, data);
} else if (requestCode == AppConstants.ACTION_REQUEST_GALLERY && resultCode == Activity.RESULT_OK) {
if(data != null) {
Uri selectedImage = data.getData();
bitmap = getBitmapFromUri(selectedImage);
setCircularBitmap(bitmap);
} else {
LogUtils.debug("path", "Gallery Data null");
}
isProfileImageUpdated = true;
super.onActivityResult(requestCode, resultCode, data);
}
}
The first condition is for device camera, and the second is for Gallery. And I have implemented runtime permissions too.
Got crash in this line:
bitmap = (Bitmap) data.getExtras().get("data");
Anything I'm missing out for Pixel XL? Didn't find any post pointing out to Pixel XL.
EDIT:
Crash Report:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1025, result=-1, data=Intent { }} to activity {com.paramsolutions.leadshare/com.paramsolutions.leadshare.activity.EditProfileActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.BaseBundle.get(java.lang.String)' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4089)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4132)
at android.app.ActivityThread.-wrap20(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1533)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.BaseBundle.get(java.lang.String)' on a null object reference
at com.paramsolutions.leadshare.activity.EditProfileActivity.onActivityResult(EditProfileActivity.java:323)
at android.app.Activity.dispatchActivityResult(Activity.java:6932)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4085)
The line number points to the above-mentioned line, and I've Moto G4 Plus, which is also 7.0. I don't have that issue. Anything different in Pixel XL?
Does the app crashes for all the Android 7.0 devices.
If your targetSdkVersion is 24 or higher, we have to use FileProvider class to give access to the particular file or folder to make them accessible for other apps.
Steps to replace file:// uri with content:// uri:
Add this to your manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
</manifest>
then create a provider_paths.xml file in xml folder under res folder. Folder may be needed to create if it doesn't exist. The content of the file is shown below. It describes that we would like to share access to the External Storage at root folder (path=".") with the name external_files.
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
The final step is to change the line of code below in
Uri photoURI = Uri.fromFile(createImageFile());
to
Uri photoURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile());
Related
I want to open the camera, save the photo and pass it to an ImageView. However, I am able to take the photo but I cannot confirm the photo creation. I can also cancel or retake the photo but not confirm.
This is the related code that I used. It doesn't even get to onActivityResult when pressing the confirm button.
camera_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED){
requestPermissions(new String[]{ Manifest.permission.CAMERA }, CAMERA_CODE);
}else{
OpenCamera();
}
}
});
private void OpenCamera(){
File file = new File(DbHelper.ImageFolder.getPath() + File.separator + NewImageFileName());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", file);
image_path = uri.getPath();
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, CAMERA_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length == 0 || grantResults[0] == PackageManager.PERMISSION_DENIED)
return;
switch (requestCode){
case CAMERA_CODE:
OpenCamera();
break;
case GALLERY_CODE:
OpenGallery();
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) return;
Bitmap image = null;
switch (requestCode){
case CAMERA_CODE:
image = BitmapFactory.decodeFile(image_path);
break;
case GALLERY_CODE:
try {
image = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData());
image_path = NewImageFileName();
// Then saves to local
} catch (IOException e) {
e.printStackTrace();
}
break;
default:
return;
}
food_image.setImageBitmap(image);
}
My cell phone is OnePlus 7 Pro. My code works on another phone I borrowed. I wonder if my code is wrong (or it needs some code to handle compatibility) or there is something wrong with the device. On the emulator (Pixel 3 XL), it keeps taking photos and there is no confirm.
My project is here.
Code posted is here.
---Update---
It seems there is something wrong with other settings. Now it keeps processing the image. And my emulator doesn't get the image set.
The main problem of mine is I forgot to check the permission of writing memory as saving the picture taken requires it:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }, WRITE_STORAGE);
Adding this properly would make my camera work.
My source code is here.
You are using "OnePlus 7 Pro" to run your app
and it's OS is Android 9.0 (Pie).
If you target to run your application that OS is upper then N you need some file sharing setting
1.Specify the FileProvider
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
...
</application>
</manifest>
2.Specify sharable directories in res/xml/filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>
Change some code in on onActivityResult
//*******
Bitmap image = null;
switch (requestCode){
case CAMERA_CODE:
Bundle extras = data.getExtras();
image = (Bitmap) extras.get("data");
break;
//*****
Android Developer Code Link for file sharing provider setting
Android Developer Code Link how to Take Photos
I am having a bit of trouble finding the solution to my problem. This is the third day working on it (not that I work on it all day) but still I am unable to fix it.
I am adding a function to my app which is taking a photography, shorten it, compressing it and converting it to Base64 so I can send it as part of the information for a document. I have been able to do all of it but I am having two problems that I suppose are related to each other. The first one and the one I am having troubles with is that if after taking the photography successfully the user decides that he needs to change it by taking another photography a second time, the app crashes. Sometimes I have been able to take a second photography but a third time the app crashes. The user can decide how many pictures wants to take for finally deciding what to send, so I am not planing on limiting him to just take one.
I am thinking that it has to do with memory leaks or something with the Activity lifecycle (which is also related to the memory as I understand) that gives me the problem.
The second problem is that if the user decides to take a photography and is taken successfully, then decides to take another but later he decides to not take it giving a resultCode = 0 as expected, the Activity seems to be refreshed and all the EditText data stays intact but the previous photography is not shown. I could get it back in the onResume callback but I am not sure if there is something better to do.
Here are the snippets to my code:
public void tomarFotografia(View view) {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException e) {
e.printStackTrace();
}
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this, "com.thesageelder.pmt.remisiones", photoFile);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
// cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
List<ResolveInfo> resolvedIntentActivities = getPackageManager().queryIntentActivities(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolvedIntentInfo : resolvedIntentActivities) {
String packageName = resolvedIntentInfo.activityInfo.packageName;
grantUriPermission(packageName, photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
}
}
private File createImageFile() throws IOException {
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
"RemisionPMT" + new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US).format(Calendar.getInstance().getTime()),
".jpg",
storageDir
);
currentPhotoFile = image.getAbsolutePath();
return image;
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) {
File photoFile = new File(currentPhotoFile);
try {
Bitmap fullPhoto = MediaStore.Images.Media.getBitmap(getContentResolver(), Uri.fromFile(photoFile));
float aspectRatio = fullPhoto.getWidth() / (float) fullPhoto.getHeight();
int w = 1024;
int h = Math.round(w / aspectRatio);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Bitmap.createScaledBitmap(fullPhoto, w, h, true).compress(Bitmap.CompressFormat.JPEG, 70, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
EncodedPhoto = Base64.encodeToString(byteArray, Base64.DEFAULT);
try {
ExifInterface exif = new ExifInterface(currentPhotoFile);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
int rotationDegrees = 0;
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotationDegrees = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotationDegrees = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotationDegrees = 270;
break;
}
Bitmap photoThumnail = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(currentPhotoFile), fullPhoto.getScaledWidth(getResources().getDisplayMetrics()) / 4, fullPhoto.getScaledHeight(getResources().getDisplayMetrics()) / 4);
if (rotationDegrees != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(rotationDegrees);
photoThumnail = Bitmap.createBitmap(photoThumnail, 0, 0, photoThumnail.getWidth(), photoThumnail.getHeight(), matrix, true);
}
ivFotoPreview.setImageBitmap(photoThumnail);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
And this is the logcat:
18819-18819 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.thesageelder.pmt.remisiones, PID: 18819
java.lang.RuntimeException: Unable to resume activity {com.thesageelder.pmt.remisiones/com.thesageelder.pmt.remisiones.RemisionView}:
java.lang.RuntimeException: Failure delivering result
ResultInfo{who=null, request=2000, result=-1, data=null} to activity
{com.thesageelder.pmt.remisiones/com.thesageelder.pmt.remisiones.RemisionView}:
java.lang.NullPointerException
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2797)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2826)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.access$800(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1200)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2000, result=-1, data=null} to activity
{com.thesageelder.pmt.remisiones/com.thesageelder.pmt.remisiones.RemisionView}:
java.lang.NullPointerException
at android.app.ActivityThread.deliverResults(ActivityThread.java:3384)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2784)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2826)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.access$800(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1200)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at java.io.File.fixSlashes(File.java:185)
at java.io.File.(File.java:134)
at com.thesageelder.pmt.remisiones.RemisionView.onActivityResult(RemisionView.java:749)
at android.app.Activity.dispatchActivityResult(Activity.java:5467)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3380)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2784)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2826)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.access$800(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1200)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
at dalvik.system.NativeStart.main(Native Method)
I have placed a breakpoint in the very first line in the onActivityResult super.onActivityResult(requestCode, resultCode, data); and the app crashes without even stopping there.
I have no idea what is the problem and being unable to debug it, I finally decide to ask here after some days searching for it. I think that all the other questions and answers I have read are related to not managing the result code or not reading correctly the data portion of the delivery result for the Activity. In my case I am expecting a resultCode different to -1 from the user and the data portion returns null since I want the full photography (since I found no way to having it from the data's extras).
Any help would be appreciated and sorry for the long question, I hope that writing this much detail would help understand my problem.
Not sure if it helps or not, but I am using an LG L70 with KitKat 4.4.2 to test it. Maybe with a more powerful device I would not have the problem, but the devices that the users are going to use wont be that more powerful.
Regards,
Elder
PD1: I do have the permission for <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> and <uses-permission android:name="android.permission.CAMERA"/>
PD2: I am leaving the entire camera function that I used here for some one that may need help with the camera and the FileProvider, additional to the previous code, it is needed that this is added to the Manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="[package]"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
and a XML resource file file_paths.xml with this:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="RemisionesPMT" path="Android/data/[package]/files/Pictures" />
</paths>
It took me six hours to figure it out.
On android devices below Nougat I have no problem saving images in the device's external storage and then storing the file path and displaying the image with Picasso.
However when tested on a Nougat device, I started getting FileUriExposedException whenever I start the camera intent.
I added fileprovider in manifest and also added a filepaths.xml
Manifest.xml:
<provider
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true"
android:name="android.support.v4.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
filepaths.xml:
<paths>
<external-path name="mediaimages" path="." />
</paths>
Here's my code
MainActivity.java
Intent takePicture = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
String authorities = getPackageName() + ".fileprovider";
File image = getTempFile(AddListingPage2Activity.this);
try {
image.createNewFile(); //Getting ignore warning
} catch (IOException e) {
e.printStackTrace();
}
Uri imageUri = FileProvider.getUriForFile(AddListingPage2Activity.this, authorities, image);
mImageFileUri = imageUri;
takePicture.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(takePicture, CAMERA_REQ);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case CAMERA_REQ:
if (resultCode == RESULT_OK) {
//How to get bitmap and create file to store in storage
Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile(mImageFileUri.getPath()); //returns null
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), mImageFileUri); //returns null as well
} catch (IOException e) {
e.printStackTrace();
}
}
break;
}
private File getTempFile(Context context) {
final File path = new File(Environment.getExternalStorageDirectory(), context.getPackageName());
if (!path.exists()) {
path.mkdir(); //Getting ignored warning
}
return new File(path, "myImage.jpg");
}
How do I save the image file and retrieve the file path in OnActivityResult?
I figured out why the camera app was unable to save the image. The app was supposed to save an image in ./packagename/myImage.jpg but myImage.jpg was created as a directory. After I deleted the folder and tried running the app, I was finally able to save the image.
You should be update filepaths.xml
<paths>
<external-path
name="external_files"
path="." />
</paths>
and Mainifest.xml file
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
My Sample app is working well with the earlier version(before Android M) but getting crash while performing compression after being fetched from internal storage since height and width is coming -1.
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
After doing some research, I come to the conclusion that the the file is getting corrupted at the time of clicking an image in Android N & M, may be since I'm saving the images as a temporary file not sure.
The following code I'm using for clicking an image:
public void takePhoto() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File f = null;
try {
f = setUpPhotoFile();
mCurrentPhotoPath = f.getAbsolutePath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(ctx.getContext(),"com.example.fileprovider", f);
}
else{
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
}
} catch (IOException e) {
e.printStackTrace();
f = null;
mCurrentPhotoPath = null;
}
ctx.startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);
}
fileprovider.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="images" path="Pictures/AIADMK/"/>
</paths>
manifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/fileprovider" />
</provider>
The below is the crash error:
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Pictures/AIADMK/IMG_20170428_122804_1986080142.jpg
at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:711)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:400)
at helper.ImageHelper.takePhoto(ImageHelper.java:108)
at helper.ImageHelper$1.onClick(ImageHelper.java:73)
at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:1134)
at android.widget.AdapterView.performItemClick(AdapterView.java:315)
at android.widget.AbsListView.performItemClick(AbsListView.java:1193)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3231)
at android.widget.AbsListView$3.run(AbsListView.java:4207)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5769)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Where am I going wrong?
Add required permissions check before requesting to camera
and in addition
For Android N,
add this code in onCreate() method of your Application class.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
No need to specify provider or path with this.
Note-Using provider is still the best way to do same task.
hope it help someone !
check permission for marshmallow
if (Build.VERSION.SDK_INT >= 23 &&
(ContextCompat.checkSelfPermission(yourActivityContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(yourActivityContext, new String[]{Manifest.permission.CAMERA}, 2//requestCode);
} else {
selectImage();
}
And override onRequestPermissionsResult of Activity
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 2: //same request code you provided in code above
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
selectImage();
}
break;
}
}
Check for permission for API 23 and above refer this
http://www.coderzheaven.com/2016/07/29/simple-example-on-using-camera-access-permission-in-android-marshmallow/
Check your onActivityResult() is it give you output in bitmap or uri.
3.If you are getting output in uri convert it into bitmap.
The issue is the latest version of Android because in Android M & N we have to use FileProvider in order to persist the file and for earlier version we can use Uri.fromFile(f).
I do have to change my fileprovider.xml as listed below:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<external-path name="myexternalimages" path="Pictures/AIADMK" />
</paths>
I updated my nexus 5 Android OS version to 5.1.1 and also updated the Google Camera and Google Photos application. After this, when ever I tried to capture image and Crop it, my application crashes with the following Error:
FATAL EXCEPTION: main
Process: com.app.test, PID: 4857
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2, result=-1, data=Intent { typ=image/jpeg }} to activity {com.app.test/com.app.test.newActivity.activities.TestActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Parcelable android.os.Bundle.getParcelable(java.lang.String)' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:3574)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
at android.app.ActivityThread.access$1300(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Parcelable android.os.Bundle.getParcelable(java.lang.String)' on a null object reference
at com.app.test.newActivity.activities.TestActivity.onActivityResult(TestActivity.java:127)
at android.app.Activity.dispatchActivityResult(Activity.java:6192)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3570)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
at android.app.ActivityThread.access$1300(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Previously it was working fine. The code I have used is as follows:
Image Capture code:
try {
Intent imageCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (imageCapture.resolveActivity(getContext().getPackageManager()) != null) {
imageCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory().getAbsolutePath() + Constants.image_path)));
startActivityForResult(imageCapture, Constants.CAMERA_IMAGE_CAPTURE);
}
} catch (ActivityNotFoundException anfe) {
Toast.makeText(getContext(), "device doesn't support capturing images!", Toast.LENGTH_SHORT).show();
}
Image Crop code
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK) {
if (requestCode == CAMERA_IAMGE_CROP) {
Bundle extras = intent.getExtras();//intent.getExtras() is always returns NULL here
Bitmap thePic = extras.getParcelable("data");
//setImageOnImageView(thePic);
} else if (requestCode == Constants.CAMERA_IMAGE_CAPTURE)) {
processCapturedImage();
}
}
}
private void processCapturedImage() {
try {
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + Constants.image_path;
File file = new File(path);
if (file.exists()) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bm = BitmapFactory.decodeFile(path, options);
int rotate = AndroidUtils.getRotateValue(file.getAbsolutePath());
if (rotate != 0) {
Debug.print("Profile pic rotation value is not 0.");
/****** Image rotation ****/
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
}
picUri = getImageUri(getApplicationContext(), bm);
performCropAction();
} else {
Tools.showToast(EditProfileActivity.this, "Error occurred, please try again.");
}
} catch (Exception e) {
Debug.printException(e);
}
}
private void performCropAction() {
try {
Intent cropAction = new Intent("com.android.camera.action.CROP");
cropAction.setDataAndType(picUri, "image/*");
cropAction.putExtra("crop", "true");
cropAction.putExtra("aspectX", 1);
cropAction.putExtra("aspectY", 1);
cropAction.putExtra("outputX", AS.getInPixels(100));
cropAction.putExtra("outputY", AS.getInPixels(100));
cropAction.putExtra("return-data", true);
startActivityForResult(cropAction, CAMERA_IAMGE_CROP);
}
catch (ActivityNotFoundException anfe) {
Toast.makeText(this, "your device doesn't support the crop action!", Toast.LENGTH_SHORT).show();
}
}
As you can see,
Bundle extras = intent.getExtras();
The intent.getExtras() here is always returns NULL.
Any help is really appreciated!
Thanks.
Above android 5.0 Crop function return URI in onActivityResult so handle it with version of phone accordingly.
Bitmap selectedBitmap;
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Bundle extras = data.getExtras();
selectedBitmap = extras.getParcelable("data");
}
else{
Uri uri = data.getData();
selectedBitmap=MediaStore.Images.Media.getBitmap(this.getContentResolver(),uri);
}
Hope this helps!
I have same problem. The new CROP action doesn't use method onActivityResult(). Resolution: copy file to folder where you want to save cropped image, start "com.android.camera.action.CROP" with file copied earlier. When user clicks "Save" button after crop - the new copied file will be replaced with cropped image. Ask me if you have any questions.
#nikash
Solution number one: If you want use only standard android Camera's Crop activity, you should know that the new (Android 5.1.1) Camera's crop activity doesn't return anything for onActivityResult() method. It just crops the image you provide. If you will provide Crop Activity with original image - it will replace the original image with new cropped one. It can't save it separately. You can create a copy of the original image (don't put this copy to your application's data folder, cause Camera's crop activity has no permissions to work with any files in your activity's folder). After, you can send to Camera's crop activity the new link of copied image. Then, after cropping, you can move cropped (before copied) image to any folder you want.
Solution number two: Better than first. You can use this image cropper:
https://android-arsenal.com/details/1/207
Second solution is better than first one. Easy to use, easy to implement, and you don't care about other devices bugs. It will work everywhere without standard Camera's Crop Activity. Your application could be API7 and above. Don't forget to put "compile 'com.edmodo:cropper:1.0.1'" to your gradle file. Compile. And enjoy.
Example usage:
Main activity:
Intent cropIntent = new Intent(Main.this, CropActivity.class);
cropIntent.putExtra("from", input.getAbsolutePath());
cropIntent.putExtra("to", output.getAbsolutePath());
startActivityForResult(cropIntent, CROP_IMAGE);
Crop activity:
Bitmap bmp = BitmapFactory.decodeFile(new File(getIntent().getExtras().getString("from")).getAbsolutePath());
cropImageView.setImageBitmap(bmp);
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getIntent().putExtra("bitmap", cropImageView.getCroppedImage());
setResult(RESULT_OK, getIntent());
finish();
}
});
After you can receive it in Main activity:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && data != null && requestCode == CROP_IMAGE)
{
croppedBitmap.setImageBitmap((Bitmap) data.getParcelableExtra("bitmap"));
}
}
Crop Image Activity layout should contain:
<com.edmodo.cropper.CropImageView
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/CropImageView"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:aspectRatioX="5" />
Here you can find more about usage: https://github.com/edmodo/cropper/wiki