1

I am trying to provide a functionality in my app that the media or storage files used in my application can be moved to SD card by the user.

I am trying to use the code as described in below link

http://www.java-samples.com/showtutorial.php?tutorialid=1523

But I get a permission exception. When I searched for getting that permission, I see that I have to root the device. I don't want to root my device, as it is illegal, no? Is there any android device model that comes rooted from the beginning itself from the manufacturer?

Earlier also I used to see a "Move To SD Card" option in the app settings, but I don't see that option any more. I also saw that most of the file browser applications installed in my device are unable to create a folder on the SD card,

Please share some light on what's the best recommended way to implement this feature. We are supporting android 4.4 to 8.0

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
user1699790
  • 51
  • 3
  • 10
  • Rooting your device is not illegal: you purchased your device, it's YOURS. You can do anything to it. Even hammering it flat. – Phantômaxx Apr 12 '18 at 09:29
  • ha ha ... my rooting the device may not be illegal, but asking users to root the device to use the features of the application developed by me is probably un ethical, as manufacturer does not provide ways to root the device, it is given by a hacker – user1699790 Apr 12 '18 at 10:40
  • No, well, not really unethical. But annoying, that's it. Not all the users feel adventurous (and you have to be!) and they might not want to risk bricking their device. – Phantômaxx Apr 12 '18 at 12:07

2 Answers2

1

Yes writing to the sd card is blocked in modern Android versions.

Mostly you have read acces to the whole sd card.

Writing only to one app specific directory which if you are lucky is available in the second item returned by getExternalFilesDirs().

If you want to write to the whole sd card then use the Storage Access Framework.

For instance Intent.ACTION_OPEN_DOCUMENT_TREE.

greenapps
  • 11,154
  • 2
  • 16
  • 19
  • tx, lucky :) ? how a directory for app name gets created in sd card ? Moreover, why google does not provide proper documentation about it being blocked ? Without that, it is so difficult to convince customers ! I am ok writing to app specific directories....any tutorial how to use open_document_tree – user1699790 Apr 12 '18 at 08:14
  • That directory is created by Android OS. Just google for that intent and you find examples. – greenapps Apr 12 '18 at 08:23
0

If you haven't done so already, you will need to give your app the correct permission to write to the SD Card by adding the line below to your Manifest:

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

Getting runtime permissions

You should be checking if the user has granted permission of external storage by using:

if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    Log.v(TAG,"Permission is granted");
    //File write logic here
    return true;
}

If not, you need to ask the user to grant your app a permission:

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

Of course these are for marshmallow devices only so you need to check if your app is running on Marshmallow:

 if (Build.VERSION.SDK_INT >= 23) {
      //do your check here
 }

Be also sure that your activity implements OnRequestPermissionResult

The entire permission looks like this:

public  boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG,"Permission is granted");
            return true;
        } else {

            Log.v(TAG,"Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        Log.v(TAG,"Permission is granted");
        return true;
    }
}

Permission result callback:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
        Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
        //resume tasks needing this permission
    }
}

Also

SD Card directory is /sdcard but you shouldn't be hard coding it. Instead, make a call to Environment.getExternalStorageDirectory() to get the directory:

File sdDir = Environment.getExternalStorageDirectory();

Code to write into external storage

Source

/** Method to check whether external media available and writable. This is adapted from
   http://developer.android.com/guide/topics/data/data-storage.html#filesExternal */

 private void checkExternalMedia(){
      boolean mExternalStorageAvailable = false;
    boolean mExternalStorageWriteable = false;
    String state = Environment.getExternalStorageState();

    if (Environment.MEDIA_MOUNTED.equals(state)) {
        // Can read and write the media
        mExternalStorageAvailable = mExternalStorageWriteable = true;
    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        // Can only read the media
        mExternalStorageAvailable = true;
        mExternalStorageWriteable = false;
    } else {
        // Can't read or write
        mExternalStorageAvailable = mExternalStorageWriteable = false;
    }   
}

/** Method to write ascii text characters to file on SD card. Note that you must add a 
   WRITE_EXTERNAL_STORAGE permission to the manifest file or this method will throw
   a FileNotFound Exception because you won't have write permission. */

private void writeToSDFile(){

    // Find the root of the external storage.
    // See http://developer.android.com/guide/topics/data/data-  storage.html#filesExternal

    File root = android.os.Environment.getExternalStorageDirectory();

    // See http://stackoverflow.com/questions/3551821/android-write-to-sd-card-folder

    File dir = new File (root.getAbsolutePath() + "/download");
    dir.mkdirs();
    File file = new File(dir, "myData.txt");

    try {
        FileOutputStream f = new FileOutputStream(file);
        PrintWriter pw = new PrintWriter(f);
        pw.println("Hi , How are you");
        pw.println("Hello");
        pw.flush();
        pw.close();
        f.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        Log.i(TAG, "******* File not found. Did you" +
                " add a WRITE_EXTERNAL_STORAGE permission to the   manifest?");
    } catch (IOException e) {
        e.printStackTrace();
    }   
}

/** Method to read in a text file placed in the res/raw directory of the application. The
  method reads in all lines of the file sequentially. */

private void readRaw(){
    InputStream is = this.getResources().openRawResource(R.raw.textfile);
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr, 8192);    // 2nd arg is buffer size

    // More efficient (less readable) implementation of above is the composite expression
    /*BufferedReader br = new BufferedReader(new InputStreamReader(
            this.getResources().openRawResource(R.raw.textfile)), 8192);*/

    try {
        String test;    
        while (true){               
            test = br.readLine();   
            // readLine() returns null if no more lines in the file
            if(test == null) break;

        }
        isr.close();
        is.close();
        br.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

}
}

In addition to that

Shared storage may not always be available, since removable media can be ejected by the user.

Daksh Gargas
  • 3,498
  • 2
  • 23
  • 37
  • `Also SD Card directory is /sdcard but you shouldn't be hard coding it. Instead, make a call to Environment.getExternalStorageDirectory() to get the directory:`. Nonsense. That gives external storage. Not a path to removable SD card. Who upvoted this bad info? – greenapps Apr 12 '18 at 08:27
  • From Androd M onwards you also need to ask for runtime permissions. You did not even mention them. But all you told is for external memory. Not for a removable SD card. So your answer is no answer to the question. – greenapps Apr 12 '18 at 08:35
  • @greenapps Just updated the answer, pl have a look. Thanks! – Daksh Gargas Apr 12 '18 at 08:42
  • Your answer is still not to the point as it has nothing to do with access to a removable SD card. This has been said before. What can we do to make you understand? Sigh... – greenapps Apr 12 '18 at 08:46
  • If you'll see the Tutorial he's referring to, I guess the answer can help this. – Daksh Gargas Apr 12 '18 at 08:48
  • Wrong tutorial to begin with as it does not write to SD card either. – greenapps Apr 12 '18 at 08:51
  • Exactly, therefore following my code will help him out. – Daksh Gargas Apr 12 '18 at 08:51
  • My god... No. Your code has nothing to do with writing to an SD card. – greenapps Apr 12 '18 at 08:52
  • Are you kidding me? Check the method `writeToSdFile()` – Daksh Gargas Apr 12 '18 at 08:54
  • You can name it as if it would write to an SD card yes. But it writes to ExternalStorageDirectory which is NOT a removable SD card. – greenapps Apr 12 '18 at 08:56
  • Read this https://developer.android.com/reference/android/content/Context.html#getExternalFilesDir(java.lang.String) – Daksh Gargas Apr 12 '18 at 08:58
  • No i will not read that. You better quote from it. And further you seem quite unwilling to see the difference between external memory and an SD card. A pitty. – greenapps Apr 12 '18 at 09:00
  • Returns the absolute path to the directory on the primary shared/EXTERNAL storage device where the application can place persistent files it owns. These files are internal to the applications, and not typically visible to the user as media. – Daksh Gargas Apr 12 '18 at 09:01
  • Yes. Thats all true. But that is not the removeble SD card. If you do not put an SD card in your device it will still work. – greenapps Apr 12 '18 at 09:02
  • Yea, that's why Shared storage may not always be available, since removable media can be ejected by the user. **Media state can be checked using getExternalStorageState(File)**. where `File` contains path of your SD card storage. – Daksh Gargas Apr 12 '18 at 09:03
  • That is wrong info. Old info. For Android 3. It just is not true already a long time. Forget it. – greenapps Apr 12 '18 at 09:05
  • Okay, so does your answer helps to solve the solution? P.S I've keen to know that, not being sarcastic. – Daksh Gargas Apr 12 '18 at 09:06