Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can i check MANAGE_EXTERNAL_STORAGE(all file access) in android? #105

Closed
GAGANsinghmsitece opened this issue Feb 15, 2022 · 7 comments
Closed

Comments

@GAGANsinghmsitece
Copy link

Hello, I am developing a cordova application for which i need excess to all files. Due to scoped storage for android 11, I need MANAGE_EXTERNAL_STORAGE for it. I tried requesting the permission cordova.plugins.permissions.MANAGE_EXTERNAL_STORAGE but it returns undefined. How can i request it or do i need to extend the plugin for this permission?

@hardslk
Copy link

hardslk commented Mar 22, 2022

I am also facing same issue so please provide solution I am stuck on play store.

@NeoLSN
Copy link
Owner

NeoLSN commented Mar 22, 2022

To request the undefined permission, you can do like this.
permissions.hasPermission('android.permission.MANAGE_EXTERNAL_STORAGE')

@NeoLSN NeoLSN closed this as completed Mar 22, 2022
@GAGANsinghmsitece
Copy link
Author

It does not work. I tried doing it in my cordova app but it returns false even though the permission is already been granted,

@NeoLSN
Copy link
Owner

NeoLSN commented Mar 23, 2022

According to this document - https://developer.android.com/training/data-storage/manage-all-files
Have you declared this permission on the manifest?
And maybe the permission string is android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION

@GAGANsinghmsitece
Copy link
Author

GAGANsinghmsitece commented Mar 23, 2022

ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION is the intent which is being used to set the permission. Also, i believe we need to check Environment.isExternalStorageManager for permission. Furthermore, there are multiple permissions for which we need to open intents to grant permission starting from API 30. I strongly believe this plugin will need huge re-work in near future. I do not know guidelines/how-to to create cordova plugin. If you can direct me to some adequate resources, i can create a cordova plugin for MANAGE_EXTERNAL_STORAGE permission.

@ragul02
Copy link

ragul02 commented Jul 13, 2022

Any solution for this issue?

@Barry1990
Copy link

Barry1990 commented Dec 9, 2022

Sorry, because my project is in a hurry, I changed the code so that it can be used.

this.androidPermissions.requestPermission('android.permission.MANAGE_EXTERNAL_STORAGE')
package com.android.plugins;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.pm.PackageManager;

import androidx.core.content.ContextCompat;


/**
 * Created by JasonYang on 2016/3/11.
 */
public class Permissions extends CordovaPlugin {

    private static String TAG = "Permissions";

    private static final String ACTION_CHECK_PERMISSION = "checkPermission";
    private static final String ACTION_REQUEST_PERMISSION = "requestPermission";
    private static final String ACTION_REQUEST_PERMISSIONS = "requestPermissions";

    private static final int REQUEST_CODE_ENABLE_PERMISSION = 55433;
    private static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469; // For SYSTEM_ALERT_WINDOW

    private static final String KEY_ERROR = "error";
    private static final String KEY_MESSAGE = "message";
    private static final String KEY_RESULT_PERMISSION = "hasPermission";

    private CallbackContext permissionsCallback;

    @Override
    public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
        if (ACTION_CHECK_PERMISSION.equals(action)) {
            cordova.getThreadPool().execute(new Runnable() {
                public void run() {
                    checkPermissionAction(callbackContext, args);
                }
            });
            return true;
        } else if (ACTION_REQUEST_PERMISSION.equals(action) || ACTION_REQUEST_PERMISSIONS.equals(action)) {
            cordova.getThreadPool().execute(new Runnable() {
                public void run() {
                    try {
                        requestPermissionAction(callbackContext, args);
                    } catch (Exception e) {
                        e.printStackTrace();
                        JSONObject returnObj = new JSONObject();
                        addProperty(returnObj, KEY_ERROR, ACTION_REQUEST_PERMISSION);
                        addProperty(returnObj, KEY_MESSAGE, "Request permission has been denied.");
                        callbackContext.error(returnObj);
                        permissionsCallback = null;
                    }
                }
            });
            return true;
        }
        return false;
    }

    @Override
    public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
        if (permissionsCallback == null) {
            return;
        }

        JSONObject returnObj = new JSONObject();
        if (permissions != null && permissions.length > 0) {
            //Call checkPermission again to verify
            boolean hasAllPermissions = hasAllPermissions(permissions);
            addProperty(returnObj, KEY_RESULT_PERMISSION, hasAllPermissions);
            permissionsCallback.success(returnObj);
        } else {
            addProperty(returnObj, KEY_ERROR, ACTION_REQUEST_PERMISSION);
            addProperty(returnObj, KEY_MESSAGE, "Unknown error.");
            permissionsCallback.error(returnObj);
        }
        permissionsCallback = null;
    }
   
    private void checkPermissionAction(CallbackContext callbackContext, JSONArray permission) {
        if (permission == null || permission.length() == 0 || permission.length() > 1) {
            JSONObject returnObj = new JSONObject();
            addProperty(returnObj, KEY_ERROR, ACTION_CHECK_PERMISSION);
            addProperty(returnObj, KEY_MESSAGE, "One time one permission only.");
            callbackContext.error(returnObj);
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            JSONObject returnObj = new JSONObject();
            addProperty(returnObj, KEY_RESULT_PERMISSION, true);
            callbackContext.success(returnObj);
        } else {
            String permission0;
            try {
                permission0 = permission.getString(0);
            } catch (JSONException ex) {
                JSONObject returnObj = new JSONObject();
                addProperty(returnObj, KEY_ERROR, ACTION_REQUEST_PERMISSION);
                addProperty(returnObj, KEY_MESSAGE, "Check permission has been failed." + ex);
                callbackContext.error(returnObj);
                return;
            }
            JSONObject returnObj = new JSONObject();
            if ("android.permission.SYSTEM_ALERT_WINDOW".equals(permission0)) {
                Context context = this.cordova.getActivity().getApplicationContext();
                addProperty(returnObj, KEY_RESULT_PERMISSION, Settings.canDrawOverlays(context));
            } else if("android.permission.MANAGE_EXTERNAL_STORAGE".equals(permission0)){
                this.checkPermissionNew(callbackContext);
                return;
            }
            else {
                addProperty(returnObj, KEY_RESULT_PERMISSION, cordova.hasPermission(permission0));
            }
            callbackContext.success(returnObj);
        }
    }

    private void requestPermissionAction(CallbackContext callbackContext, JSONArray permissions) throws Exception {
        if (permissions == null || permissions.length() == 0) {
            JSONObject returnObj = new JSONObject();
            addProperty(returnObj, KEY_ERROR, ACTION_REQUEST_PERMISSION);
            addProperty(returnObj, KEY_MESSAGE, "At least one permission.");
            callbackContext.error(returnObj);
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            JSONObject returnObj = new JSONObject();
            addProperty(returnObj, KEY_RESULT_PERMISSION, true);
            callbackContext.success(returnObj);
        } else if (hasAllPermissions(permissions) || hasPermissionNew()) {
            JSONObject returnObj = new JSONObject();
            addProperty(returnObj, KEY_RESULT_PERMISSION, true);
            callbackContext.success(returnObj);
        } else {
            permissionsCallback = callbackContext;
            String[] permissionArray = getPermissions(permissions);

            if(permissionArray.length == 1 && permissionArray[0].equals("android.permission.MANAGE_EXTERNAL_STORAGE")){
                requestPermissionNew(callbackContext);
                return;
            }


            if (permissionArray.length == 1 && "android.permission.SYSTEM_ALERT_WINDOW".equals(permissionArray[0])) {
                Log.i(TAG, "Request permission SYSTEM_ALERT_WINDOW");

                Activity activity = this.cordova.getActivity();
                Context context = this.cordova.getActivity().getApplicationContext();

                // SYSTEM_ALERT_WINDOW
                // https://stackoverflow.com/questions/40355344/how-to-programmatically-grant-the-draw-over-other-apps-permission-in-android
                // https://www.codeproject.com/Tips/1056871/Android-Marshmallow-Overlay-Permission
                if (!Settings.canDrawOverlays(context)) {
                    Log.w(TAG, "Request permission SYSTEM_ALERT_WINDOW start intent because canDrawOverlays=false");
                    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                            Uri.parse("package:" + activity.getPackageName()));
                    activity.startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
                    return;
                }
            }
            cordova.requestPermissions(this, REQUEST_CODE_ENABLE_PERMISSION, permissionArray);
        }
    }

    private String[] getPermissions(JSONArray permissions) {
        String[] stringArray = new String[permissions.length()];
        for (int i = 0; i < permissions.length(); i++) {
            try {
                stringArray[i] = permissions.getString(i);
            } catch (JSONException ignored) {
                //Believe exception only occurs when adding duplicate keys, so just ignore it
            }
        }
        return stringArray;
    }

    private boolean hasAllPermissions(JSONArray permissions) throws JSONException {
        return hasAllPermissions(getPermissions(permissions));
    }

    private boolean hasAllPermissions(String[] permissions) throws JSONException {

        for (String permission : permissions) {
            if(!cordova.hasPermission(permission)) {
                return false;
            }
        }

        return true;
    }

    private void addProperty(JSONObject obj, String key, Object value) {
        try {
            if (value == null) {
                obj.put(key, JSONObject.NULL);
            } else {
                obj.put(key, value);
            }
        } catch (JSONException ignored) {
            //Believe exception only occurs when adding duplicate keys, so just ignore it
        }
    }
	
	// New methods
	 private boolean hasPermissionNew(){
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){
            return Environment.isExternalStorageManager();
        }else{
            Context context=this.cordova.getActivity().getApplicationContext();
            int readcheck= ContextCompat.checkSelfPermission(context,android.Manifest.permission.READ_EXTERNAL_STORAGE);
            int writecheck=ContextCompat.checkSelfPermission(context,android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
            return (readcheck== PackageManager.PERMISSION_GRANTED && writecheck==PackageManager.PERMISSION_GRANTED);
        }
    }

    private void checkPermissionNew(CallbackContext callbackContext) {
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){
            if(Environment.isExternalStorageManager()){
                JSONObject response=new JSONObject();
                addProperty(response,KEY_RESULT_PERMISSION,true);
                callbackContext.success(response);
            }else{
                JSONObject response=new JSONObject();
                addProperty(response,KEY_RESULT_PERMISSION,false);
                callbackContext.success(response);
            }
        }else{
            JSONObject response=new JSONObject();
            addProperty(response,KEY_RESULT_PERMISSION,false);
            callbackContext.success(response);
        }
        callbackContext.error(" An error has occurred");
    }

    private void requestPermissionNew(CallbackContext callbackContext) throws Exception{
        if(hasPermissionNew()){
            JSONObject result=new JSONObject();
            addProperty(result,KEY_RESULT_PERMISSION,true);
            callbackContext.success(result);
        } else{
            permissionsCallback = callbackContext;

            Activity activity =this.cordova.getActivity();
            Context context=this.cordova.getActivity().getApplicationContext();

            Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
            Intent intent = new Intent();
            intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
            intent.setData(uri);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            cordova.setActivityResultCallback (this);
            cordova.startActivityForResult(this,intent,11);
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants