0

I'm writing a testing program and I want to serialize some of my test result to a file. I keep on getting this annoying permission denied exception. To make things easier, I write a small sample code and still get the same permission denied warning. Here is my code, I use getExternalStorageDirectory to get the /mnt/sdcard/ directory:

private void writetry(){
        try {
            File sdCard = Environment.getExternalStorageDirectory();
            Log.d("can write", String.valueOf(sdCard.canWrite()));
            Log.d("ExternalStorageState", Environment.getExternalStorageState());
            File file = new File(sdCard, "VisitedScreen.temp");
            //file.createNewFile();
            FileOutputStream f = new FileOutputStream(file);
             byte[] buf = "Hello".getBytes();
             f.write(buf);
             f.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

And here is what logcat print out:

07-12 12:28:47.288: D/can write(253): false
07-12 12:28:47.288: D/ExternalStorageState(253): mounted
07-12 12:28:47.297: W/System.err(253): java.io.FileNotFoundException: /sdcard/VisitedScreen.temp
07-12 12:28:47.437: W/System.err(253):  at org.apache.harmony.luni.platform.OSFileSystem.open(OSFileSystem.java:244)
07-12 12:28:47.437: W/System.err(253):  at java.io.FileOutputStream.<init>(FileOutputStream.java:97)
07-12 12:28:47.437: W/System.err(253):  at java.io.FileOutputStream.<init>(FileOutputStream.java:69)

I declared my Junit testing Manifest file as: (Actually it's the wrong place to set the permission)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.mandaria.tippytipper.test"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7" />

    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="net.mandaria.tippytipper" />

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

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <uses-library android:name="android.test.runner" />
    </application>


</manifest>

Any suggestion is appreciated!

Added: I copy the same code to a normal android program, it works, and the sdCard.canWrite() return true. But in Android Junit testing project it's not working. Anyone knows why??

Problem solved: Thanks for all those of you have replied. It's because I haven't add the in original Android program. I also noted that I don't need to add any permission to Junit test project. It's very interesting that the write action happened in the testing project, but permission is required in the original project. I'm wondering what if I'm doing black box testing against an .apk file. I can't change the permission from the byte code right?

Wei Yang
  • 895
  • 3
  • 15
  • 26
  • The reason is at a glance, the SD card is in read-only state. Look at it again. Why is 'D/can write' showing `false`, and then immediately after that, 'D/ExternalStorageState` says 'mounted'? – t0mm13b Jul 12 '12 at 19:55
  • Are you mounting the storage when the app is running within the emulator? – t0mm13b Jul 12 '12 at 19:59
  • OP: Can you re-edit your question to explicitly state whether that manifest is part of the testing project or the main project?... see @Devunwired's comment below DtMilano's answer.. :) – t0mm13b Jul 12 '12 at 21:06
  • @t0mm13b thanks for reminding me. I re-edit the question. – Wei Yang Jul 12 '12 at 22:40

3 Answers3

3

The uses-permission

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

should be added to your main project's manifest. Remember that tests are run in the same process as the main application.

Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
  • 1
    @t0mm13b We can't assume that. The manifest above is for the TEST project, this permission needs to live in the MAIN project. – devunwired Jul 12 '12 at 21:01
  • The OP should have clarified that the manifest is part of the test project and not the main project - good catch! Ask the OP in the comment above? :) – t0mm13b Jul 12 '12 at 21:02
  • 1
    See the instrument and uses-library tags, is very likely the tests' mainfest – Diego Torres Milano Jul 12 '12 at 21:18
  • Thanks! @dtmilano I'm also wondering if I'm testing against an apk file, what should i do? – Wei Yang Jul 12 '12 at 22:39
  • Application Under Test and Tests must be signed with same certificate, so you cannot test a third party APK using this method. On the other hand, tests will be able to write to its data directory independently of the AUT. – Diego Torres Milano Jul 12 '12 at 23:39
1

Change this line:

File sdCard = Environment.getExternalStorageDirectory();

to this:

File sdCard = new File(Environment.getExternalStorageDirectory().getPath());
t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • Thanks! but sdCard.canWrite() still return false. The filenotfound exception still exists after I push an empty file to /sdcard/ – Wei Yang Jul 12 '12 at 20:21
  • Seems the only difference between the two statement is change the directory from /mnt/sdcard/ to /sdcard/ – Wei Yang Jul 12 '12 at 20:22
  • What android emulator version are you using? It sounds like the sdcard on the emulator is in read-only? Can you check that? – t0mm13b Jul 12 '12 at 20:24
  • I check that, I can push file to emulator's sdcard directory, so I guess it's not emulator's problem. However, I find that the code is successfully executed in normal Android project. While in Android Junit testing project, it still throw this exeption. Do you have a clue about what's the difference between the two? Thanks! – Wei Yang Jul 12 '12 at 20:30
0

I ran into the same problem. To fix this I not only had to add the permission tag to the Main manifest, but I also had to add the tag to the manifest of the module containing the unittest.

Permission tag:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Rob
  • 2,466
  • 3
  • 22
  • 40