Android: Crash after Image Crop when updated OS Version to 5.1.1

3.4k views Asked by At

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.

3

There are 3 answers

2
Rahim Rahimov On

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.

0
Rahim Rahimov On

@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

0
Himanshu On

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!