Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android app can't read external storage files

Tags:

file

android

I'm creating an app for a private use only... it's not so important then, respect your time :P

What I want to make is an app that reads from a database and plays sounds. I've already made the database and I am able to play sound from res/raw folder. However, there are thousands of files to play and some new ones will be a part of the app and other will be deleted in the future. So, adding a simple file makes me to download the whole app (~1 GB) each time (or maybe I'm wrong?). Instead, I thought of reading an Excel file and playing sounds from SD card then. But I can't... as far as i know:

Apps are not allowed to write (delete, modify ...) to external storage except to their package-specific directories.

I put the files into the /storage/emulated/0/Android/data/my_package_folder/files folder. I've read really many topics and nothing helped me.

Environment.MEDIA_MOUNTED.equals(extStorageState) //returns true
Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState) //returns false

I tried a few ways of creating new file object or playing the sound with the mediaplayer (as I've said before, there's no problem with playing res/raw files) but file.exists always returns false or sound doesn't play:

String filePath = getExternalFilesDir(null) + "/myfile.mp3"; //returns correct file path
File file = new File(filePath);

OR

File file = new File(getExternalFilesDir(null).getPath(), "myfile.mp3");

OR

MediaPlayer mp;
mp = MediaPlayer.create(this, Uri.parse(getExternalFilesDir(null).getPath() + "/myfile.mp3"));

The minSdkVersion is set to 19 so I don't need that line in Manifest:

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

I have included that line and nothing changed:

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

I was also trying to do that with other file extensions. Also, the solution from here didn't help. My phone is Samsung Galaxy Grand Prime (SM-G530FZ), Android v. 5.0.2. Help, please! :)

like image 994
kuznikowski Avatar asked Jul 06 '16 14:07

kuznikowski


3 Answers

Here is the code @Nisarg, had to clean it a bit:

import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import java.io.File;

public class MainActivity extends AppCompatActivity implements OnClickListener {

Button readExcelButton;
static String TAG = "ExelLog";
MediaPlayer mpintro;

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

    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
        Toast.makeText(this, "Permission checking", Toast.LENGTH_SHORT).show();
        checkPermission();
    }

    readExcelButton = (Button) findViewById(R.id.readExcel);
    readExcelButton.setOnClickListener(this);

}

public void onClick(View v)
{
    switch (v.getId())
    {
        case R.id.readExcel:
            String filePath = getExternalFilesDir(null) + "/p0000.mp3";
            File file = new File(filePath);
            file.setReadable(true);
            file.setWritable(true);

            if (!isExternalStorageAvailable() || isExternalStorageReadOnly()) {
                Toast.makeText(this, "Ext storage not available or read only", Toast.LENGTH_SHORT).show();
            }
            else {
                Toast.makeText(this, "Ext storage available", Toast.LENGTH_SHORT).show();
            }

            if (file.exists()){
                Toast.makeText(this, "File found", Toast.LENGTH_SHORT).show();
            }
            else {
                Toast.makeText(this, getExternalFilesDir(null) + "/p0000.mp3 - File not found", Toast.LENGTH_LONG).show();
            }

            break;
    }
}

private void checkPermission() {
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {//Can add more as per requirement

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

    } else {

    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 123: {

            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED)     {
                //Peform your task here if any
            } else {

                checkPermission();
            }
            return;
        }
    }
}

public static boolean isExternalStorageReadOnly() {
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
        return true;
    }
    return false;
}

public static boolean isExternalStorageAvailable() {
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
        return true;
    }
    return false;
}

}

like image 77
kuznikowski Avatar answered Sep 27 '22 17:09

kuznikowski


if your targetSdk is 23 than you have to check permissions like this for marshmallow and above devices

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
    checkPermission();
}
else {
}


private void checkPermission() {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {//Can add more as per requirement

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

        } else {

        }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                   String permissions[], int[] grantResults)   
   {
    switch (requestCode) {
        case 123: {


 if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED)     {
   //Peform your task here if any
    } else {

        checkPermission();
    }
        return;
    }
}
}
like image 33
Nisarg Avatar answered Sep 27 '22 18:09

Nisarg


You also have to have the permission READ_EXTERNAL_STORAGE; Either write or read is not enough when it comes to external storage, as you have to use both

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

You can also read more about external data writing in the declaration

The reason you cannot read is because you didn't add that permission. A good rule is if you only need to read, only use read permission. But if you need to write you need the write and the read permission

EDIT:

When loading the directory, try this:

file.setReadable(true);
file.setWritable(true);

Note: the value 'file' here is for the directory, not each separate file(all though that works fine too)

From the declaration:

This permission is enforced starting in API level 19. Before API level 19, this permission is not enforced and all apps still have access to read from external storage.

If I am correct that means the permission has to be there from API 19 and up, but not before API 19

like image 38
Zoe stands with Ukraine Avatar answered Sep 27 '22 17:09

Zoe stands with Ukraine