I am writing an app that will access the WhatsApp/Media/WhatsApp Images directory located in a user's android phone and sets different photos as background depending on the user's location.
I see that the location directory WhatsApp is directly under Device Storage when I access it using a Folder Manager kind of an app installed on my phone. However, I am not able to find it when I do a search under / from my app's code. My code is here:
private void findWhatsappMediaDirectories() {
String whatsappMediaDirectoryName = "/";
displayTreeStructure(whatsappMediaDirectoryName);
}
private void displayTreeStructure(String whatsappMediaDirectoryName) {
File whatsappMediaDirectory = new File(whatsappMediaDirectoryName);
Log.e(this.getClass().toString(), "In " + whatsappMediaDirectoryName);
File[] mediaDirectories = whatsappMediaDirectory.listFiles();
if (mediaDirectories == null) {
Log.e(this.getClass().toString(), whatsappMediaDirectoryName + " does not have any files");
}
else if (mediaDirectories.length != 0) {
for (File mediaDirectory : mediaDirectories) {
if (mediaDirectory.getName().equals("WhatsApp")) {
if (mediaDirectory.isDirectory()) {
Log.e(this.getClass().toString(), mediaDirectory.getAbsolutePath());
displayTreeStructure(mediaDirectory.getAbsolutePath());
}
}
}
}
}
This keeps failing with no directory name displayed. Can someone please point out what the path should be to access the location?
Found the solution. The problem was in my understanding of the concept of internal and external storage in Android devices. The right way to access WhatsApp/Media directory is as follows:
File whatsappMediaDirectoryName = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media");
Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/.Statuses"
Related
I am currently working on an app, that goes through your phone and lists all available MP3 files. I managed to get this done and search for everything on the internal storage, but didnt manage to find a way using the envoirment to get to the sd card, when one is installed. This is my code - u will see a missing part when SD card is TRUE. Can you complete it?
public List<string> ReturnPlayableMp3(bool sdCard)
{
List<string> res = new List<string>();
string phyle;
if(sdCard)
{
// missing
}
else
{
try
{
var path1 = Android.OS.Environment.ExternalStorageDirectory.ToString();
var mp3Files = Directory.EnumerateFiles(path1, "*.mp3", SearchOption.AllDirectories);
foreach (string currentFile in mp3Files)
{
phyle = currentFile;
res.Add(phyle);
}
}
catch (Exception e9)
{
Toast.MakeText(ApplicationContext, "ut oh\n" + e9.Message, ToastLength.Long).Show();
}
}
return res;
}
}
It would need to return the exact same thing as it does for the internal storage only this time for the sd card. Right now, what is beeing returned is:
""/storage/emulated/0""
I hope you can help me. Thank you!
SO I found the place it is: /storage/05B6-2226/
But the digits refer to only MY sd card. How do I get this path programatically?
Take a look at these methods:
Context.GetExternalFilesDir
Returns the absolute path to the directory on the primary external
filesystem (that is somewhere on Environment.ExternalStorageDirectory)
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.
Context.GetExternalFilesDirs
Returns absolute paths to application-specific directories on all
external storage devices where the application can place persistent
files it owns. These files are internal to the application, and not
typically visible to the user as media.
I've been searching for a couple of days with a lot of solutions that just ended up giving you the 'external' built in storage. Finally found this solution for the 'removable' SD Card and wanted to post it here in case someone else is still looking.
How to write on external storage sd card in mashmallow in xamarin.android
//Get the list of External Storage Volumes (E.g. SD Card)
Context context = Android.App.Application.Context;
var storageManager = (Android.OS.Storage.StorageManager)context.GetSystemService(Context.StorageService);
var volumeList = (Java.Lang.Object[])storageManager.Class.GetDeclaredMethod("getVolumeList").Invoke(storageManager);
List<Java.IO.File> ExtFolders = new List<Java.IO.File>();
//Select the Directories that are not Emulated
foreach (var storage in volumeList)
{
Java.IO.File info = (Java.IO.File)storage.Class.GetDeclaredMethod("getDirectory").Invoke(storage);
if ((bool)storage.Class.GetDeclaredMethod("isEmulated").Invoke(storage) == false && info.TotalSpace > 0)
{
//Get Directory Path
Console.WriteLine(info.Path);
}
}
Just wanna share my answer, where I have get the extStorages Path and I use this method in my simple file browser app.
public static string[] GetRemovableStorages()
{
List<string> extStorage = new List<string>();
//If this throws exception
string storageDir = (string)Environment.StorageDirectory;
//Try this
string storageDir = Directory.GetParent (Environment.ExternalStoragePublicDirectory).Parent.FullName;
string[] directories = Directory.GetDirectories(storageDir);
foreach(string dir in directories)
{
try
{
var extStoragePath = new Java.IO.File(dir);
bool isRemovable = Environment.InvokeIsExternalStorageRemovable(extStoragePath);
if(isRemovable) extStorage.Add(extStoragePath.AbsolutePath);
else return null;
}
catch
{
}
}
return extStorage.ToArray();
}
Elikill58's answer throws exception no such method "getDirectory" in my case but I recommend Elikill58's answer
I delete the file (camera file) like that:
public static void deleteFile(File file) {
if (file != null && file.exists()) {
if (!file.delete()) {
LogUtils.LOGE(TAG, "Delete file failed: " + file.getAbsolutePath());
} else {
LogUtils.LOGD(TAG, "Delete file successful: " + file.getAbsolutePath());
}
}
}
The delete indicates successful, but if I check on Gallery App on my phone, I can see this strange stuff:
It's on my Android 4.4.x. With my another mobile on Android 6.x there is no problem.
Could you help me guys?
As #CommonsWare said, since you are saving your file in the public storage, the gallery app will find the file and keep track, after you remove the gallery needs to update the references to now show the image anymore.
To avoid that you should always save your files in the private storage, you can find more info about storages here: https://developer.android.com/training/basics/data-storage/files.html
We've just fallen foul of the new permissions that apply to writing files to sd cards (external storage) on Android 4.4 (EACCES Permission Denied)
Prior to KitKat we set our writable folder like this:
mfolder = Environment.getExternalStorageDirectory().getPath() + "/appfiles";
However after hours of searching I've come to the conclusion, rightly or wrongly that on 4.4 devices to enable writing of files this needs to be changed to:
mfolder = Environment.getExternalStorageDirectory().getPath() + "/Android/data/com.xyz.abc/appfiles";
So mfolder would be something like: /mnt/sdcard/Android/data/com.xyz.abc/appfiles
Is this correct, do we create a folder like the one above on the sdcard to enable 4.4 devices to write files?
mfolder is a String that we save to shared preferences.
Then we have this code that runs once if API>=19 that changes the mfolder String and then copies all the files from the old folder to the new 'kitkat' folder.
if (android.os.Build.VERSION.SDK_INT>=19){
if (!mfolder.contains("/Android/data/com.xyz.abc/appfiles")){
if (prefs.getBoolean("kitkatcheck", false)==false){
//update mfolder from
// /mnt/sdcard/appfiles
// to
// /mnt/sdcard/Android/data/com.xyz.abc/appfiles
String prekitkatfolder = mfolder;
String kitkatfolder = mfolder.replace("/appfiles", "/Android/data/com.xyz.abc/appfiles");
mfolder = kitkatfolder;
try {
File sd = new File(mfolder);
if(!sd.exists() || !sd.isDirectory()) {
sd.mkdirs();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), "Error creating Kitkat folder!\n" + e.toString(), Toast.LENGTH_LONG).show();
return;
}
prefEditor.putString("patternfolder", mfolder);
prefEditor.putBoolean("kitkatcheck", true);
prefEditor.commit();
//copy files and folder from old appfiles folder to new.
AllFiles.clear();
listFilesAndFilesSubDirectories(prekitkatfolder);
if (AllFiles.size()>0){
for (File child : AllFiles ) {
try {
File dest = new File(child.toString().replace(prekitkatfolder, kitkatfolder));
try {
String filePath = dest.getPath().substring(0, dest.getPath().lastIndexOf(File.separator));
File subfolder = new File(filePath);
if(!subfolder.exists() || !subfolder.isDirectory()) {
subfolder.mkdirs();
}
} catch (Exception ex) {
}
copyFile(child, dest);
} catch (Throwable t) {
}
}
}
}
}
I then notify the user that their files have been copied to the new folder and that due to the new permissions they would have to manually delete the old prekitkatfolder folder. I guess they will only be able to do this if they have a stock file manager or if they unmounted sd card and place it in a PC, due to the new 4.4 permissions?
Also, for us it appears that these 4.4 permissions are not affecting all our users with Kitkat. Some can still write to the original folder location on their external storage and some get the EACCES (Permission Denied) error. Can anyone throw any light on why this might be, one would think it would apply to all 4.4 devices using external storage?
As we have no actual 4.4 device we are having to test this code using the emulator (API 19) but we do not get the EACCES Permission Denied error. So we released a beta version with code above and have been told that the copied files ended up in internal storage, how can that be?
Any ideas what we're doing wrong, thanks in advance
Updated solution.
This sets and also creates the folder in the correct place for KitKat.
mfolder = this.getExternalFilesDir("asubfoldername").getAbsolutePath();
However, this isn't full-proof, if the Android device has both an internal and external secondary storage locations, the above will use the internal one. Not really what we want as we require path to removable sdcard or better still the path to the secondary storagelocation with the most free available space.
File[] possible_kitkat_mounts = getExternalFilesDirs(null);
Note the "s" on the end of getExternalFilesDirs. This creates an array of secondary external storage locations.
for (int x = 0; x < possible_kitkat_mounts.length; x++) {
//Log.d("test", "possible_kitkat_mounts " + possible_kitkat_mounts[x].toString());
boolean isgood=false;
if (possible_kitkat_mounts[x] != null){
isgood = test_mount(possible_kitkat_mounts[x].toString());
if (isgood==true){
arrMyMounts.add(newymounts(Device_get_device_info(possible_kitkat_mounts[x].toString()), possible_kitkat_mounts[x].toString()));
}
}
}
//sort arrMyMounts size so we can use largest
Collections.sort(arrMyMounts, new Comparator<mymounts>(){
public int compare(mymounts obj1, mymounts obj2){
return (obj1.avaliablesize > obj2.avaliablesize) ? -1: (obj1.avaliablesize > obj2.avaliablesize) ? 1:0 ;
}
});
if (arrMyMounts.size()>0){
mfolder = arrMyMounts.get(0).name + "/asubfoldername";
//Log.d("test", "selected kitkat mount " + kitkatfolder);
}else{
//do something else...
}
From the array of possible_kitkat_mounts we check via test_mount to see if we can actually write to the selected location and if successful we add that location to arrMyMounts.
By sorting arrMyMounts we can then get the location with the most available free space.
Hey presto, arrMyMounts.get(0).name is a kitkat secondary storage location with the most free space.
Google has blocked write access to external storage devices in Android 4.4. Until they change it there is no way to revert it back without root.
More info: https://groups.google.com/forum/#!msg/android-platform/14VUiIgwUjY/UsxMYwu02z0J
It might be working on some devices with Kitkat which have minisd card slot. It is confusing :(
I develop an app which collects some data from internet. Then save it to a temporary folder. To build this app I need to create and access a folder ( just for the purpose of app, not for the user). How can I do it?
this code is to create folder:
File direct = new File(Environment.getExternalStorageDirectory() + "/New Folder");
if(!direct.exists())
{
(direct.mkdir()) //directory is created;
}
try it may help you
File mFile;
onCreate()
mFile= new File(Environment.getExternalStorageDirectory()+"/temp/";
mFile.mkdir();
onDestroy();
mFile.delete();
try out this...
private void makeFolder(){
File root = new File(Environment.getExternalStorageDirectory()
+ File.separator + getString(R.string.folder_name));
boolean mainfolderexist = root.exists();
if (!mainfolderexist) {
try {
if (Environment.getExternalStorageDirectory().canWrite()) {
root.mkdirs();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
All The best
You should really check this other SO answer: https://stackoverflow.com/a/6485850/65716
Aside from the fact that you have to completely manage your use of the space, etc, caching on external storage requires more permission for your app.
See http://developer.android.com/reference/android/content/Context.html#getCacheDir()
"Apps require no extra permissions to read or write to the returned path, since this path lives in their private storage."
For app use only, I would recommend to use Context.getDir() for retrieving the directory if the files is used by our app only and don`t want to be visible to users by file browsers.
// No need to check if exist, created automatically.
File tempRoot = context.getDir("temp", Context.MODE_PRIVATE);
// do something
i have a problem with my code that is supposed to write some data string to my sdcard. i use a class to do this:
public class CVS {
private String path;
private String filename;
private File dir;
private File file;
private FileWriter fw;
public CVS() {
path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/traffic/";
filename = "data.cvs";
file = new File(path, filename);
createDir();
}
private void createDir() {
dir = new File(path);
if(!dir.exists()) {
if(file.mkdirs() == false) {
Log.d(Config.LOGTAG, "UHOH!!!!!!!!!!!!!!!!!!!!!!!!");
}
}
else Log.d(Config.LOGTAG, "dir exists");
}
public void writeToFile(String data) {
try {
fw = new FileWriter(file);
fw.append(data); Log.d(Config.LOGTAG, "data saved to file...");
}
catch(Exception e) {
Log.d(Config.LOGTAG, "file: " + e.getMessage());
}
}
}
this results ALWAYS in an exeption being caught in writeToFile(), saying "permission denied". actually, i set permissions to WRITE_EXTERNAL_STORAGE in the manifest. so - what am i doing wrong!?
additional info: real device with sd card mounted. no emulator. android 2.2. if i create the dir myself, the problem wont go away :(
Either:
Your manifest is wrong, or
Your external storage is mounted on your development machine, or
Your manual concatenation of your directory is wrong
Your code is ok but still you can add a check for whether sdcard is inserted or not, if you run this code and sdcard is not inserted then it will throw an exception, good practice is that you should always catch the exeptions.
you can check sdcard by following code...
if (android.os.Environment.getExternalStorageState().equals
(android.os.Environment.MEDIA_MOUNTED))
{
//code or logic if sd card is inserted....
}
else
{
Log.e("Exception","SD Card not found!");
}
All of the answers are needed, but if it's a Samsung device, then you need to append "/external_sd/" to the path - because they decided they needed to dork with our minds and break the API:
"http://developer.samsung.com/forum/board/thread/view.do?boardName=GeneralB&messageId=162934&messageNumber=1381&startId=zzzzz~&searchType=TITLE&searchText=sdcard