Max Max - 27 days ago 11
Android Question

Android 6 - Programmatically copy an app file to another folder

I have an app running in Android 6 that streams data in from a BLE device. This works fine when using something like:

myFile = new File(getExternalFilesDir(filepath), MyData);

The resulting file is at a location that looks like:

Filepath: /storage/emulated/0/Android/data/my_package/files/my_file

I'd like to copy this file to a new folder that is not buried in the mass under the Android/data directory so a user can easily find and retrieve the data connecting to a phone/tablet via the USB cable. So far, I've been unable to figure out how to do this ... or if it's even possible. Anything I try seems to result in a permission exception.

I'd like this folder to be at the same level as ~/Android/data if possible. If not, are there any alternatives? Such as putting the data out on the SD card.

I've read through many posts and articles on the Android file system. It's all very confusing and vague. And new versions of Android seem to change the way things work. If anyone knows of a clear and concise explanation relative to Android 6 (Marshmallow) (maybe even with working examples!) please let me know.

Thanks, Max

Max Max
Answer

I used the permission suggestion from Adeel Turk. I didn't need to check the build version, since I'm using only Android 6 (API 23).

//
// Get storage write permission
//
public  boolean isStoragePermissionGranted(int requestCode) {
    if (ContextCompat.checkSelfPermission(MyActivity.this,android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
            == PackageManager.PERMISSION_GRANTED) {

        //Now you have permission
        return true;
    } else {


        ActivityCompat.requestPermissions(MyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
        return false;
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

        //Now you have permission

        // Check file copy generated the request
        // and resume file copy
        if(requestCode == WFileRequest)
            try {
                copyFile(OriginalDataFileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

While this got through the permission exceptions, it didn't answer the question of how to create a folder outside of the default application directory. The following code gets permission and creates a folder at /storage/emulated/0 called AppData which appears on the top level of Device storage. The permission request code WFileRequest was set to 4 as in Adeel Turk's example, but I understand you can use any number. The permission request callback then checks the request code and invokes the copyFile routine again with the name of the file that was originally written.

Most of this code used examples from a couple other posts in this forum at how to create a folder in android External Storage Directory? and How to copy programmatically a file to another directory?

    public void copyFile(String SourceFileName) throws FileNotFoundException, IOException
{
    String filepath = "";
    //
    // Check permission has been granted
    //
    if (isStoragePermissionGranted(WFileRequest)) {
        //
        // Make the AppData folder if it's not already there
        //
        File Directory = new File(Environment.getExternalStorageDirectory() + "/AppData");
        Directory.mkdirs();

        Log.d(Constants.TAG, "Directory location: " + Directory.toString());
        //
        // Copy the file to the AppData folder
        // File name remains the same as the source file name
        //
        File sourceLocation = new File(getExternalFilesDir(filepath),SourceFileName);
        File targetLocation = new File(Environment.getExternalStorageDirectory() + "/AppData/" + SourceFileName);

        Log.d(Constants.TAG, "Target location: " + targetLocation.toString());

        InputStream in = new FileInputStream(sourceLocation);
        OutputStream out = new FileOutputStream(targetLocation);

        // Copy the bits from instream to outstream
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }

}