chaquo / chaquopy

Chaquopy: the Python SDK for Android
https://chaquo.com/chaquopy/
MIT License
753 stars 129 forks source link

Unable to read the file from sdcard folder in Python script #312

Closed VPrasannakumar closed 4 years ago

VPrasannakumar commented 4 years ago

Hi, I am running python script from android Java code using chaquopy.

JAVA source code -

 if (!Python.isStarted()) {
            Python.start(new AndroidPlatform(this));
        }
        Python python = Python.getInstance();
        PyObject pythonFile = python.getModule("generate_FP");
        File path = new File(Environment.getExternalStorageDirectory() + "/media/audio/ringtones/Albg.mp3");
     if(path.exists()) {
           // PyObject helloWorldString = pythonFile.callAttr("generate_fp", "/media/audio/ringtones/Albg.mp3");
            PyObject helloWorldString = pythonFile.callAttr("generate_fp", path.toString());
            Log.v("MainActivity   ", "Python - " + helloWorldString.toString());
        }else
            Log.v("MainActivity   ", "Python - file is not exist" );

Python script -

 print('filename is',filename)
    filename = str(Environment.getExternalStorageDirectory())+filename
    if os.path.exists(filename):
        print('true')
    else :
        print('false')
    print(os.access('filename',os.R_OK))  **Output - False**

Error message java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gaian.testpython/com.gaian.testpython.MainActivity}: com.chaquo.python.PyException: PermissionError: [Errno 13] Permission denied: '/storage/emulated/0/media/audio/ringtones/Albg.mp3'

Please help for resolving this issue Thank you.

mhsmith commented 4 years ago

You need to request the external storage permission. See here for an example.

VPrasannakumar commented 4 years ago

I have given external storage permission also `

` Please help to resolve this problem.
mhsmith commented 4 years ago

On newer versions of Android it's not enough to list them in your AndroidManifest anymore, you also need to interactively request the user's permission. See the answer in my previous link.

VPrasannakumar commented 4 years ago

Dear mhsmith, I added that functionality already. Could you please check the below for activity class

`public class MainActivity extends AppCompatActivity {

final static String TAG ="MainActivity";

private static final int REQUEST_PERMISSIONS = 100;
private static final String PERMISSIONS_REQUIRED[] = new String[]{
        android.Manifest.permission.READ_EXTERNAL_STORAGE
        , Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.ACCESS_NETWORK_STATE
};

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

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

        checkPermissions();
    }

}

private void navigatetoBrowser(){

    if (!Python.isStarted()) {
        Python.start(new AndroidPlatform(this));
    }

    Python python = Python.getInstance();
    PyObject pythonFile = python.getModule("generate_FP");
    File path = new File(Environment.getExternalStorageDirectory() + "/media/audio/ringtones/Albg.mp3");

   if(path.exists()) {
        //PyObject helloWorldString = pythonFile.callAttr("generate_fp", "/media/audio/ringtones/Albg.mp3");
       PyObject helloWorldString = pythonFile.callAttr("generate_fp", path.toString());
        Log.v("MainActivity   ", "Python - " + helloWorldString.toString());
    }else
        Log.v("MainActivity   ", "Python - file is not exist" );

}

private void checkPermissions() {
    boolean permissionsGranted = checkPermission(PERMISSIONS_REQUIRED);
    if (permissionsGranted) {
        navigatetoBrowser();
        Toast.makeText(this, "You've granted all required permissions!", Toast.LENGTH_SHORT).show();
    } else {
        boolean showRationale = true;
        for (String permission : PERMISSIONS_REQUIRED) {
            showRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
            if (!showRationale) {
                break;
            }
        }

        ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_REQUIRED, REQUEST_PERMISSIONS);

    }
}
private boolean checkPermission(String permissions[]) {
    for (String permission : permissions) {
        if (ContextCompat.checkSelfPermission(getApplicationContext(), permission) != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
    }
    return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    Log.d(TAG, "requestCode: " + requestCode);
    //Log.d(TAG, "Permissions:" + Arrays.toString(permissions));
    //Log.d(TAG, "grantResults: " + Arrays.toString(grantResults));

    if (requestCode == REQUEST_PERMISSIONS) {
        boolean hasGrantedPermissions = true;
        for (int i = 0; i < grantResults.length; i++) {
            if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                hasGrantedPermissions = false;
                break;
            }
        }

        if (!hasGrantedPermissions) {

            finish();
        }else{

            navigatetoBrowser();
        }

    } else {

        finish();
    }
}

} `

mhsmith commented 4 years ago

It looks correct to me, but I know the rules around external storage have changed in recent versions of Android.

Try adding some code to read the same file in Java using a FileInputStream. If it works in Java but not in Python, then please post details here (including which devices the problem happens on), and I'll look into it further. If it doesn't work work in Java either, then your problem isn't related to Chaquopy and you should seek help elsewhere.

VPrasannakumar commented 4 years ago

Dear Smith, I am able to read the file from sdcard using Fileinputstream in JAVA but not in the python and also I have created media player. Its playing.

Device details - Android OS 10 and Model Samsung - A50S JAVA code

 File path = new File(Environment.getExternalStorageDirectory() + "/media/audio/ringtones/Albg.mp3");

        if (path.exists()) {
        try {
            // Read File and Content
            FileInputStream fin = null;
            fin =  new FileInputStream (path);

            // read inside if it is not null (-1 means empty)
                Log.v(TAG,"file size- "+fin.read());

            fin.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

            try {
                mediaPlayer = new  MediaPlayer();
                mediaPlayer.setDataSource(path.getAbsolutePath());
                mediaPlayer.prepare();
                mediaPlayer.start();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mediaPlayer.stop();

            if (!Python.isStarted()) {
                Python.start(new AndroidPlatform(this));
            }
            Python python = Python.getInstance();
            PyObject pythonFile = python.getModule("generate_FP");

                 PyObject helloWorldString = pythonFile.callAttr("generate_fp", "/media/audio/ringtones/Albg.mp3");
                //PyObject helloWorldString = pythonFile.callAttr("generate_fp", path.toString());
                Log.v(   TAG, "Python - " + helloWorldString.toString());
            } else
                Log.v(TAG, "Python - file is not exist");

Python sample code-

  print('filename is',filename)
    filename = str(Environment.getExternalStorageDirectory())+filename
    if os.path.exists(filename):
        **print('true')** This one is coming
    else :
        print('false')
    print(os.access('filename',os.W_OK)) - **False** coming

LOG

 Process: com.gaian.testpython, PID: 13238
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gaian.testpython/com.gaian.testpython.MainActivity}: com.chaquo.python.PyException: PermissionError: [Errno 13] Permission denied: 'ffprobe'
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3488)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3635)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2175)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:7860)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
     Caused by: com.chaquo.python.PyException: PermissionError: [Errno 13] Permission denied: 'ffprobe'
        at <python>.subprocess._execute_child(subprocess.py:1702)
        at <python>.subprocess.__init__(subprocess.py:854)
        at <python>.pydub.utils.mediainfo_json(utils.py:274)
        at <python>.pydub.audio_segment.from_file(audio_segment.py:685)
        at <python>.generate_FP.read(generate_FP.py:46)
        at <python>.generate_FP.generate_fp(generate_FP.py:119)
        at <python>.chaquopy_java.call(chaquopy_java.pyx:281)
mhsmith commented 4 years ago

OK, the PermissionError is different now, and it looks like the problem is not that it can't read the file, but that it can't run ffmpeg (#143).

Unless you can provide your own copy of ffmpeg, you'll have to either decode the MP3 to raw audio using the Android API, or use a .wav file instead.

VPrasannakumar commented 4 years ago

Thank you mhsmith. It's working with.wav file.