Download Manager Android Permissions error: write external Storage

26,174

Solution 1

You are getting this error because your app is running in Android 6.0(API level 23). From API level >= 23 you will need to check for the permission in run time. Your code is just fine for below level 23. So please check first if your user has given the permission to use the storage:

if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    Log.e("Permission error","You have permission");
    return true;
}

If not then prompt the request:

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);

Total things looks like this:

public  boolean haveStoragePermission() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.e("Permission error","You have permission");
            return true;
        } else {

            Log.e("Permission error","You have asked for permission");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //you dont need to worry about these stuff below api level 23
        Log.e("Permission error","You already have the permission");
        return true;
    }
}

And last thing :) receive the result by callback:

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
            //you have the permission now.
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(myurl));
            request.setTitle("Vertretungsplan");
            request.setDescription("wird heruntergeladen");
            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            String filename = URLUtil.guessFileName(myurl, null, MimeTypeMap.getFileExtensionFromUrl(myurl));
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
            DownloadManager manager = (DownloadManager) c.getSystemService(Context.DOWNLOAD_SERVICE);
            manager.enqueue(request);
        }
    }



Or, you can just use my custom class PermissionCheck to handle all this implementation very easily. Here is the class:

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;

/**
 * Created by Tushar on 6/30/2017.
 */

public class PermissionCheck{
    public static boolean readAndWriteExternalStorage(Context context){
        if(ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
            return false;
        }else{
            return true;
        }

    }

    public static boolean audioRecord(Context context){
        if(ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED ){
            ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.RECORD_AUDIO}, 2);
            return false;
        }else{
            return true;
        }

    }

    public static boolean readAndWriteContacts(Context context){
        if(ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS}, 3);
            return false;
        }else{
            return true;
        }

    }

    public static boolean vibrate(Context context){
        if(ActivityCompat.checkSelfPermission(context, Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.VIBRATE}, 4);
            return false;
        }else{
            return true;
        }

    }

    public static boolean sendSms(Context context){
        if(ActivityCompat.checkSelfPermission(context, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.SEND_SMS}, 5);
            return false;
        }else{
            return true;
        }

    }

    //Just like this you can implement rest of the permissions. 
}


usage:

if(PermissionCheck.readAndWriteExternalStorage(context)){
    //Your read write code.
}

if(PermissionCheck.sendSms(context)){
    //Your sms sending code.
}

**Notice that, these methods call will ask for the permissions automatically and also your onRequestPermissionsResult will be fired. :)

Solution 2

No need to do all this. Just paste below code on your onCreate() function:

private static int REQUEST_CODE=1;  

ActivityCompat.requestPermissions(this, new String[]{
    Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_CODE);

Solution 3

I had this same issue on my API 23 emulator (24 and 25 did fine) running a Custom Tabs app. I tried this solution, as well as some other variations, and I could see that I was being granted permission but the issue remained on any download attempts. When I ran the app on a real device (sans permission request code) I was automatically prompted to allow Google access to storage - not my app. I removed the code for run-time permissions and set permission for the Browser (default on the emulator) to access storage and my app worked fine. The following post provided some insight into what may be happening with the emulator: Requesting and allowing WRITE_EXTERNAL_STORAGE permission at runtime has no effects on the current session

Share:
26,174
Mark Witt
Author by

Mark Witt

Updated on July 05, 2022

Comments

  • Mark Witt
    Mark Witt almost 2 years

    I programmed an Android App that downloads a sample PDF file to the Download directory using DownloadManager. Here's the code:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vertretungsplan);
        Button dlbutton = (Button) findViewById(R.id.buttondownload);
        final Context c = this;
        dlbutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                DownloadManager.Request request = new DownloadManager.Request(Uri.parse(myurl));
                request.setTitle("Vertretungsplan");
                request.setDescription("wird heruntergeladen");
                request.allowScanningByMediaScanner();
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                String filename = URLUtil.guessFileName(myurl, null, MimeTypeMap.getFileExtensionFromUrl(myurl));
                request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
                DownloadManager manager = (DownloadManager) c.getSystemService(Context.DOWNLOAD_SERVICE);
                manager.enqueue(request);
            }
        });
    }
    

    Now, I tried to debug-run it from Android Studio on my Xperia Z3 Android 6.0. As I clicked on the download button, this error occurs:

    E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.example.markwitt.schul_app, PID: 29297
                  java.lang.SecurityException: No permission to write to /storage/emulated/0/Download/hrpsampletable.pdf: Neither user 10047 nor current process has android.permission.WRITE_EXTERNAL_STORAGE.
                      at android.os.Parcel.readException(Parcel.java:1627)
                      at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
                      at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
                      at android.content.ContentProviderProxy.insert(ContentProviderNative.java:476)
                      at android.content.ContentResolver.insert(ContentResolver.java:1240)
                      at android.app.DownloadManager.enqueue(DownloadManager.java:946)
                      at com.example.markwitt.schul_app.Vertretungsplan$1.onClick(Vertretungsplan.java:59)
                      at android.view.View.performClick(View.java:5280)
                      at android.view.View$PerformClick.run(View.java:21239)
                      at android.os.Handler.handleCallback(Handler.java:739)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:224)
                      at android.app.ActivityThread.main(ActivityThread.java:5526)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    

    Disconnected from the target VM, address: 'localhost:8600', transport: 'socket'

    (on the third line) it displays me that it has no write permission on external storage.

    But my AndroidManifest is set up correctly:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.markwitt.schul_app">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:launchMode="singleTop"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    
        <activity android:name=".Stundenplan">
    
    
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Vertretungsplan"></activity>
    </application>
    

    What do I need to do?

  • Mark Witt
    Mark Witt over 7 years
    can you tell me what the 1 in the string array means?
  • Srujan Barai
    Srujan Barai about 7 years
    Just in case if anybody has issue with Manifest.permission.WRITE_EXTERNAL_STORAGE use android.Manifest.permission.WRITE_EXTERNAL_STORAGE instead
  • Ankesh Roy
    Ankesh Roy over 4 years
    what is c in your mention line of code DownloadManager manager = (DownloadManager) c.getSystemService(Context.DOWNLOAD_SERVICE);
  • Tushar Monirul
    Tushar Monirul over 4 years
    @AnkeshRoy it is context