Accessing Storage on the Nook
The closest thing to documentation I can find having to do with file storage is this post (see below if you can't access it), but it leaves me with several questions.
I would really, really, really like a knowledgeable explanation of what paths map to what storage here, seeing as how we're supposed to hard-code them, and how precisely we're expected to access them. An actual code sample would be superlative. My best guess from messing around with this is that:
- /sdcard-> maps to the internal eMMC slot, and access is restricted. Environment.getExternalStorageDirectory(); ... still returns this.
- /media -> maps to the internal 8GB memory (I can write to this)
- /data -> ?
- ? -> maps to the optional microSD card
How can we access the external (optional, additional, the one you can pop out) sdcard, if /sdcard maps to restricted storage instead?
Now to quote the Nook developer docs:
Background There are two different partition schemes for the NOOK Color devices in market today, one with only 250MB available to applications on the /data partition and one with 4GB available to applications on the /data partition. As a result, it is imperative that applications are designed and developed in such a way as to manage space effectively. Applications which fail to do so will not be accepted for distribution via the Shop.
Area Associated Technical Recommendation or Solution if your application requires large amount of data (including but not limited to images, audio or video content), you should download those resources at runtime and store them in the larger partition of the device. If your application is going to request and store more than 100MB of data or resource you MUST abide by the the following restrictions:
Your application must clearly and explicitly state in the description provided that a large amount of data is used/delivered by the application. You MUST write your resources and data onto appropriate partition. You can detect if the device has an enlarged /data partition as follows :
StatFs stat = new StatFs("/data"); long bytesAvailable = (long)stat.getBlockSize() *(long)stat.getBlockCount(); long megAvailable = bytesAvailable / 1048576; if (megAvailable > 1000){ ... write your resources in /data } else { ... write your resources on /mnt/media ... }
To write data into your application's private space on /data
FileOutputStream fos = openFileOutput(FILENAME, Context.M开发者_StackOverflow中文版ODE_WORLD_READABLE);
Your application should NOT assume the presence of an sdcard on device, but you can test for one via a call to
Environment.getExternalStorageState(); If an SD Card is not found, your application MUST exit gracefully with a notification to the user as to the reason for the exit.
Remember, that to access the /media partition, as well as ExternalStorage you need to declare in your manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"> </uses-permission>
Okay, here's what I've learned in the past couple of weeks.
If you want to write to the internal SDcard, use Context.getFilesDir(). It'll return the private directory for your application. You can not invent your own directories on the internal flash storage (aka "/data"). You don't have permission to write anywhere other than the folder your application gets assigned. Supposedly there are two internal partitions, "/data" and "/media", but I can't get at "/media" to save my life.
You can use the external flash memory, "/sdcard", when one is available. This is the card you can pop out of the device. There are two ways to go about this:
- Store things in the folder assigned to your app (so it'll get deleted when your application is uninstalled). You can find that folder with Context.getExternalFilesDir().
- Store things wherever, either in some hard-coded path under "/sdcard/foo/bar" or in Environment.getExternalStorageDirectory() / whatever.
This post by a B&N rep (which I referenced in my question) turned out to be a bit of a red herring, "/sdcard" doesn't map to the eMMC slot, and I have no idea what "we mapped the SD card to our internal eMMC" means.
This B&N post says that "/media" is internal, but I can't write to it even though I have the proper manifest permissions... so go figure.
This is a screencap of my test device, showing what is and isn't accessible:
The code for that (note that FileUtils isn't included in the sdk by default,it's from the org.apache.commons.io lib):
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView dataView = (TextView) findViewById(R.id.data);
dataView.setText(testIt("/data"));
TextView mediaView = (TextView) findViewById(R.id.media);
mediaView.setText(testIt("/media"));
TextView mntMediaView = (TextView) findViewById(R.id.mntMedia);
mntMediaView.setText(testIt("/mnt/media"));
try {
File fd = this.getFilesDir();
if(fd != null) {
TextView fdView = (TextView) findViewById(R.id.filesDir);
fdView.setText("getFilesDir(): " + testIt(fd.toString()));
}
} catch (Exception e) {
e.printStackTrace();
}
try {
File efd = this.getExternalFilesDir(null);
if(efd != null) {
TextView efdView = (TextView) findViewById(R.id.externalFilesDir);
efdView.setText("getExternalFilesDir(): " + testIt(efd.toString()));
}
} catch (Exception e) {
e.printStackTrace();
}
try {
File esd = Environment.getExternalStorageDirectory();
if(esd != null) {
TextView esdView = (TextView) findViewById(R.id.externalStorageDirectory);
esdView.setText("getExternalStorageDirectory(): " + testIt(esd.toString()));
}
} catch (Exception e) {
e.printStackTrace();
}
try {
File espd = Environment.getExternalStoragePublicDirectory(null);
if(espd != null) {
TextView espdView = (TextView) findViewById(R.id.externalStoragePublicDirectory);
espdView.setText("getExternalStoragePublicDirectory(): " + testIt(espd.toString()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String testIt(String dir){
StatFs stat = new StatFs(dir);
long bytesAvailable = (long) stat.getBlockSize() * (long) stat.getBlockCount();
long megAvailable = bytesAvailable / FileUtils.ONE_MB;
File dirFile = new File(dir + "/test/");
dirFile.mkdir();
return dir + "/test \n canRead() " + dirFile.canRead() + ", \n canWrite() " + dirFile.canWrite() + " with " + megAvailable + "MB available";
}
First of all try the following methods:
- Context.getExternalFilesDir
- Context.getExternalCacheDir
- Environment.getExternalStoragePublicDirectory
If neither of those return you a directory where you can write to, check the following google-groups thread, and use the code provided in the last answer, which enumerates all current mount-points:
I have the same issue with Galaxy S. Until now all Android devices I
got have "mount" command available. I build a list of available volume parsing "mount" response. This is not perfect but cleaver than Android storage API.String cmd = "/system/bin/mount"; try { Runtime rt = Runtime.getRuntime(); Process ps = rt.exec(cmd); BufferedReader rd = new BufferedReader( new InputStreamReader(ps.getInputStream()) ); String rs; while ((rs = rd.readLine()) != null) { //check what you need! Log.i("MOUNT_CMD", rs); } rd.close(); ps.waitFor(); } catch(Exception e) { //... }
If it is possible to insert the microSD card in the Nook device, while it is running, you could also try the following:
mVolumeManagerReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
Log.i("MediaMounter", "Storage: " + intent.getData());
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
filter.addDataScheme("file");
context.registerReceiver(mVolumeManagerReceiver, filter);
精彩评论