Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android application crash when picking photo on new devices

Tags:

android

crash

In my application users select picture from gallery and upload. On many devices my code works perfect but on new devices (etc: samsung S5, LG G2, Samsung S4) application crashes when selecting photo. I uploaded application to Google Play Store and downloaded these devices then sended report to google play when app crashes. This is my select picture and resize code.

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Complete action using"), 1); 

public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
    int width = bm.getWidth();
    int height = bm.getHeight();
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    // create a matrix for the manipulation
    Matrix matrix = new Matrix();
    // resize the bit map
    matrix.postScale(scaleHeight, scaleHeight);
    // recreate the new Bitmap
    Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
    return resizedBitmap; }

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 if (requestCode == 1 && resultCode == RESULT_OK) {
        //Bitmap photo = (Bitmap) data.getData().getPath(); 

     Uri selectedImageUri = data.getData();
     imagepath = getPath(selectedImageUri);

     Bitmap myBitmap = getResizedBitmap(BitmapFactory.decodeFile(imagepath),200,200);

     try {
         ExifInterface exif = new ExifInterface(imagepath);
         orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
         Log.d("EXIF", "Exif: " + orientation);
         resimyon=Integer.toString(orientation);
         Matrix matrix = new Matrix();
         if (orientation == 6) {
             matrix.postRotate(90);
         }
         else if (orientation == 3) {
             matrix.postRotate(180);
         }
         else if (orientation == 8) {
             matrix.postRotate(270);
         }
         myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
     }
     catch (Exception e) {

     }


     imageview.setImageBitmap(myBitmap);
     messageText.setText("Yüklenecek dosya:" +imagepath);
     uploadButton.setEnabled(true);

 } 

These are the reports came from Samsung S5 and LG G2.

SAMSUNG S5

java.lang.SecurityException
konum: android.os.Parcel.readException

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1,     data=Intent { dat=content://media/external/images/media/1909 (has extras) }} to activity    {com.turk.bakistik/com.turk.bakistik.Profilresimyukle}: java.lang.SecurityException: Permission    Denial: reading com.android.providers.media.MediaProvider uri   content://media/external/images/media/1909 from pid=29038, uid=10236 requires    android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
at android.app.ActivityThread.deliverResults(ActivityThread.java:3663)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3706)
at android.app.ActivityThread.access$1400(ActivityThread.java:173)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1351)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5579)
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:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.SecurityException: Permission Denial: reading      com.android.providers.media.MediaProvider uri content://media/external/images/media/1909 from pid=29038, uid=10236 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
at android.os.Parcel.readException(Parcel.java:1465)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:185)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:413)
at android.content.ContentResolver.query(ContentResolver.java:464)
at android.content.ContentResolver.query(ContentResolver.java:407)
at android.app.Activity.managedQuery(Activity.java:1898)
at com.turk.bakistik.Profilresimyukle.getPath(Profilresimyukle.java:209)
at com.turk.bakistik.Profilresimyukle.onActivityResult(Profilresimyukle.java:173)
at android.app.Activity.dispatchActivityResult(Activity.java:5643)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3659)
... 11 more  

LG G2

java.lang.NullPointerException
konum: com.turk.bakistik.Profilresimyukle.getResizedBitmap
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.android.providers.media.documents/document/image:41 flg=0x1 }} to activity {com.turk.bakistik/com.turk.bakistik.Profilresimyukle}: java.lang.NullPointerException
at android.app.ActivityThread.deliverResults(ActivityThread.java:3382)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3425)
at android.app.ActivityThread.access$1300(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1248)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5105)
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:792)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.turk.bakistik.Profilresimyukle.getResizedBitmap(Profilresimyukle.java:123)
at com.turk.bakistik.Profilresimyukle.onActivityResult(Profilresimyukle.java:175)
at android.app.Activity.dispatchActivityResult(Activity.java:5467)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3378)
... 11 more

How can I fix this problem?

like image 726
sipdorus Avatar asked Oct 14 '14 07:10

sipdorus


2 Answers

Because since android kitkat, you can not get pick image local path as normal way. Please check device android version, if version < kitkat, you can use your way. If version is kitkat or later, you can try this code to get file path, then you can convert to bitmap or anything you want.

/**
 * Get a file path from a Uri. This will get the the path for Storage Access
 * Framework Documents, as well as the _data field for the MediaStore and
 * other file-based ContentProviders.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @author paulburke
 */
public static String getPath(final Context context, final Uri uri) {

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }

            // TODO handle non-primary volumes
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

/**
 * Get the value of the data column for this Uri. This is useful for
 * MediaStore Uris, and other file-based ContentProviders.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @param selection (Optional) Filter used in the query.
 * @param selectionArgs (Optional) Selection arguments used in the query.
 * @return The value of the _data column, which is typically a file path.
 */
public static String getDataColumn(Context context, Uri uri, String selection,
        String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {
            column
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}


/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
like image 86
Quoc.Dev Avatar answered Nov 12 '22 02:11

Quoc.Dev


This code goes in your onActivityResult:

AsyncTask<Uri, Void, Bitmap> imageLoadAsyncTask = new AsyncTask<Uri, Void, Bitmap>() {

    @Override
    protected Bitmap doInBackground(Uri... uris) {
        return getBitmapFromUri(uris[0]);
    }

    @Override
        protected void onPostExecute(Bitmap bitmap) {
        //crop, resize, play, do whatever with the bitmap
    }
};

imageLoadAsyncTask.execute(data.getData());

This is getting called from AsyncTask because sometimes the images/files might not be stored locally like images backed up on Google+ or Google Drive. As recommended in this Devbyte video, always call it on the background thread.

private Bitmap getBitmapFromUri(Uri uri){
    ParcelFileDescriptor parcelFileDescriptor = null;

    try {
        parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");

        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);

        parcelFileDescriptor.close();

        return bitmap;
    } catch (IOException e) {
        Log.e(tag, "Failed to load image.", e);
        e.printStackTrace();
        return null;
    } finally{
        try {
            if (parcelFileDescriptor != null) {
                parcelFileDescriptor.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(tag, "Error closing ParcelFile Descriptor");
        }
    }

}

This is from the sample code for Storage Client Sample and I've tested it on Kitkat and Lollipop.

Will test on older versions and update. If anyone tests this on older version, let me know.

Update: Tested on JellyBean and it works.

like image 34
Rahul Sainani Avatar answered Nov 12 '22 01:11

Rahul Sainani