25

I'm trying to select the image from gallery , but my application is getting exception of 'Something went wrong' message . I thought i set up the android WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE permission correctly, but i keep getting errors What should i do to have it working?

Here is my Log cat error

06-07 12:07:27.567    1692-1711/? E/DatabaseUtils﹕ Writing exception to parcel
    java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/images/media/359 from pid=2818, uid=10057 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
            at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:605)
            at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:480)
            at android.content.ContentProvider$Transport.query(ContentProvider.java:211)
            at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
            at android.os.Binder.execTransact(Binder.java:453)

Here is my Activity code

public class MainActivity extends Activity {
    private static int RESULT_LOAD_IMG = 1;
    String imgDecodableString;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void loadImagefromGallery(View view) {
        // Create intent to Open Image applications like Gallery, Google Photos
        Intent galleryIntent = new Intent(Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        // Start the Intent
        startActivityForResult(galleryIntent, RESULT_LOAD_IMG);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        try {
            // When an Image is picked
            if (requestCode == RESULT_LOAD_IMG && resultCode == RESULT_OK
                    && null != data) {
                // Get the Image from data

                Uri selectedImage = data.getData();
                String[] filePathColumn = { MediaStore.Images.Media.DATA };

                // Get the cursor
                Cursor cursor = getContentResolver().query(selectedImage,
                        filePathColumn, null, null, null);
                // Move to first row
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                imgDecodableString = cursor.getString(columnIndex);
                cursor.close();
                ImageView imgView = (ImageView) findViewById(R.id.imgView);
                // Set the Image in ImageView after decoding the String
                imgView.setImageBitmap(BitmapFactory
                        .decodeFile(imgDecodableString));

            } else {
                Toast.makeText(this, "You haven't picked Image",
                        Toast.LENGTH_LONG).show();
            }
        } catch (Exception e) {
            Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG)
                    .show();
        }
    }
}

Here is my Menifest.xml file code

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.tazeen.image_fromgallery" >

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
androidTag
  • 5,053
  • 7
  • 19
  • 28
  • on which android version u testing the code? if you testing on android m or greater then refer here to set up runtime permissions http://coderzpassion.com/android-new-runtime-permissions/ – Jagjit Singh Jun 07 '16 at 06:50
  • Thanks for the reply. I'm testing the code in minsdkversion 15 and targetSdkVersion is 23 and compileSdkVersion 23 buildToolsVersion "23.0.2" – androidTag Jun 07 '16 at 06:52
  • change your target to 22 or write code for runtime permission – J.D. Jun 07 '16 at 06:53
  • Possible duplicate of [requires android.permission.READ\_EXTERNAL\_STORAGE, or grantUriPermission() error?](http://stackoverflow.com/questions/35975659/requires-android-permission-read-external-storage-or-granturipermission-error) – Mr X Jun 07 '16 at 06:54

5 Answers5

32

For checking manual permissions for API level 23 and above i use this code.

public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 123;

public boolean checkPermissionREAD_EXTERNAL_STORAGE(
            final Context context) {
        int currentAPIVersion = Build.VERSION.SDK_INT;
        if (currentAPIVersion >= android.os.Build.VERSION_CODES.M) {
            if (ContextCompat.checkSelfPermission(context,
                    Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(
                        (Activity) context,
                        Manifest.permission.READ_EXTERNAL_STORAGE)) {
                    showDialog("External storage", context,
                            Manifest.permission.READ_EXTERNAL_STORAGE);

                } else {
                    ActivityCompat
                            .requestPermissions(
                                    (Activity) context,
                                    new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
                                    MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
                }
                return false;
            } else {
                return true;
            }

        } else {
            return true;
        }
    }

showDialog()

public void showDialog(final String msg, final Context context,
            final String permission) {
        AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
        alertBuilder.setCancelable(true);
        alertBuilder.setTitle("Permission necessary");
        alertBuilder.setMessage(msg + " permission is necessary");
        alertBuilder.setPositiveButton(android.R.string.yes,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCompat.requestPermissions((Activity) context,
                                new String[] { permission },
                                MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
                    }
                });
        AlertDialog alert = alertBuilder.create();
        alert.show();
    }

in your activity check like this.

if (checkPermissionREAD_EXTERNAL_STORAGE(this)) {
            // do your stuff..
        }

And don't forget to add onRequestPermissionsResult.

@Override
    public void onRequestPermissionsResult(int requestCode,
            String[] permissions, int[] grantResults) {
        switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // do your stuff
            } else {
                Toast.makeText(Login.this, "GET_ACCOUNTS Denied",
                        Toast.LENGTH_SHORT).show();
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions,
                    grantResults);
        }
    }

Happy Coding..

Sunil Sunny
  • 3,949
  • 4
  • 23
  • 53
V-rund Puro-hit
  • 5,518
  • 9
  • 31
  • 50
7

You have two solutions for your problem. The quick one is to lower targetApi to 22 (build.gradle file). Second is to use the new runtimePermission model: Since your target api is 23 you should add the permissions on runtime too.

if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
        != PackageManager.READ_EXTERNAL_STORAGE) {

    // Should we show an explanation?
    if (shouldShowRequestPermissionRationale(
            Manifest.permission.READ_EXTERNAL_STORAGE)) {
        // Explain to the user why we need to read the contacts
    }

    requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);

    // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
    // app-defined int constant

    return;
}

Sniplet found here: https://developer.android.com/training/permissions/requesting.html

Sunil Sunny
  • 3,949
  • 4
  • 23
  • 53
  • Can i keep this code in onCreate() and what should i write in the place of MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE – androidTag Jun 07 '16 at 06:55
  • MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is constant you can give any values for it. If you are planing to do the runTimePermission model you better read the docs first.. Docs have provided with examples too.. https://developer.android.com/training/permissions/requesting.html – Sunil Sunny Jun 07 '16 at 06:56
  • The place where you need to read External storage,That's the best place.For now you can give it in onCreate().. – Sunil Sunny Jun 07 '16 at 07:06
3

You need to set permissions explicitly to all packages match your intent. you can use this utility to do that :

List<ResolveInfo> resInfoList = getContext().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    for (ResolveInfo resolveInfo : resInfoList) {
        String packageName = resolveInfo.activityInfo.packageName;
        getContext().grantUriPermission(packageName, imageFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
izhoujinjian
  • 105
  • 5
2

There is an easy way, set an action to your "galleryIntent" so the OS will not panick (I test this on Andorid Emulator API 23 and it works):

galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

Also, don't forget to set a type too:

galleryIntent.setType("image/*");
MohammadL
  • 2,398
  • 1
  • 19
  • 36
-3
  • Change:
    Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

  • To:
    Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

=> done !

  • `Intent.ACTION_GET_CONTENT` shows a different picker and will ignore the requested `android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI`, so this change completely changes the behavior of the code. – fluidsonic Apr 28 '20 at 07:34