Search code examples
androidmotorola

Can't create folders in some specific devices


I'm struggling to find out what's going on with my code. This code snippet works on EVERY (apparently) phone, except motorola (Moto G, etc...):

private void createFolder(String folderPath) throws CantCreateFolderPathException {
    File folder = new File(folderPath);
    if (folder.mkdirs() || folder.isDirectory())
      return; //Everything ok! 

    throw new CantCreateFolderPathException(folderPath);
}

And I generate the folder path with this:

public String getFolderPath(Courseware courseware) {
    String path = getBestPath() + courseware.getSubject().getName() + File.separator;
    UnisantaApplication.Log_i("SAVE PATH:" + path);
    return path;
    //Result example: sd/unisantaapp/material/SUBJECT NAME/
}

private String getBestPath() {
    if (isExternalStorageWritable())
        return getExternalPath();
    return getInternalPath();
}

private String getExternalPath() {
    return Environment.getExternalStorageDirectory()
            .getAbsolutePath() + File.separator +
            "unisantaapp" + File.separator +
            "material" + File.separator;
}

private String getInternalPath() {
    return UnisantaApplication.getInstance().getApplicationContext()
            .getFilesDir().getAbsolutePath() + File.separator +
            "material" + File.separator;
}

folder.mkdirs keeps returning false, which causes CantCreateFolderPathException to be thrown. AGAIN, it works on all other phones that I've tested, so probably it's not a permission manifest missing:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="si.unisanta.tcc.unisantaapp" >

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

<application
      [...]

I asked for help from a friend of mine, since I don't have a motorola. I created a APK with some dialogs to help me understand the error, my steps were:

  1. Find out which path is the "best one" generated from my code: getBestPath returns ExternalStorageDirectory, but mkdirs keeps returning false

  2. Tried to change getBestPath to always returns internal path, then mkdirs returned true! At this path:

    Internal path returned (Note: Caminho: means Path:)

    But my friend claims that he can't open the file nor find it with another third-party file explorer. When he tries to open a PDF, it says:"Impossible to view PDF" and the file explorer says: "superuser not available".

  3. Frustrated with no clue of what's happening, I took a step back reverting my getBestPath method to work as expected and changed the call for folder.mkdirs() to Files.createParentDirs(folder) hoping for some more descriptive error, but instead I just received a simple:

    createParentDirs result

Well, why I can't create folder/file and open it JUST IN MOTOROLA PHONES? Anyone here already faced this? Any clues of what I'm doing wrong?


Solution

  • As @CommonsWare pointed, it's not a MOTOROLA issue, but an Android 6.0 one. I just added support to ask for permissions (runtime) and also read the article suggested (Great article, really worth it).

    I just added the following in my activity:

    private boolean hasPermissionToDownload() {
        int permissionResult = ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE);
        return permissionResult == PackageManager.PERMISSION_GRANTED;
    }
    
    private void explainOrAskPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            new AlertDialog.Builder(this)
                .setTitle(R.string.download_permission_explain_title)
                .setMessage(getString(R.string.download_permission_explain_message))
                .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        askPermission();
                    }
                })
                .show();
        }
        else {
            askPermission();
        }
    }
    
    private void askPermission() {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                PERMISSION_SAVE_DOWNLOAD_REQUEST);
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_SAVE_DOWNLOAD_REQUEST) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                downloadCourseware(lastCoursewareClicked);
            }
            else {
                new AlertDialog.Builder(this)
                    .setTitle(R.string.download_permission_denied_title)
                    .setMessage(R.string.download_permission_denied_message)
                    .setNeutralButton(R.string.ok, null)
                    .show();
            }
        }
    }