Difficulty accessing External Storage on Android - android

I am trying to access external storage on my Android App in order to access a log file so I created:
new File(getExternalFilesDir(null),"log.txt");
And then created this file in the root of my Android device.
To test the existence of the file I ran:
if (log!=null)
{
return log.exists();
}
return false;
But regardless of the files presence or lack thereof it returns false.
To find the location of where I was referencing I ran:
System.out.println(log.getAbsolutePath());
Which returns
/storage/emulated/0/Android/data/com.supportmeplus.betatester/files/log.txt
Where is this? I'd just like to access a log file that can be accessed from outside of the app later on (on a computer). Does this have to do with the fact that i'm test-running the app with an emulator?
Thanks

Related

Kotlin File(path).walkTopDown() does not find files

I'm trying to read a given directory recursively and find all folders and files. The directory and subdirectory is found, but no files.
The storage structure on my virtual device:
The code used to "walk through the given directory"
import android.util.Log
import java.io.File
// path = "/storage/1B10-1D17/ReadTest/"
class FileHelper {
fun walkTest(path: String){
File(path).walkTopDown().forEach {
// println(it)
Log.e("walkTest extension", it.extension)
if(it.isDirectory){
Log.e("walkTest", "Directory: ${it.name}")
}else{
Log.e("walkTest", "File: ${it.name}")
}
}
}
}
This will output the following:
E/walkTest extension:
E/walkTest: Directory: ReadTest
E/walkTest extension:
E/walkTest: Directory: SubFolder
In my android manifest file I have the following line and the permission is granted:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
What is the flaw in my code, how can I find the three pdf files stored in these directories?
Update 1/2
As can be seen in the screenshot below, the media access is granted:
If I run the following command (as suggested by dan1st), I get the following output, which shows that pdf file in place:
> adb shell ls /storage/1B10-1D17/ReadTest/
File_1.pdf
SubFolder
You generally have no access to arbitrary files on removable storage. This is not changed by READ_EXTERNAL_STORAGE.
Your proposed solution is to use MANAGE_EXTERNAL_STORAGE. Technically, this works, and it is a fine solution for personal-use apps. If your intention is to distribute this app, you will need to file paperwork with Google (and perhaps other app stores) justifying your use of this permission. Stores that disagree with your justification may elect to not distribute your app.
Alternatively, you can use the Storage Access Framework. Use ACTION_OPEN_DOCUMENT_TREE / ActivityResultContracts.OpenDocumentTree and let the user decide where on the user's device (or in the user's cloud storage) the user wants your app to access the user's content. You can then use DocumentFile to walk the document tree to find sub-trees and documents.

Xamarin SqlLite database in Android Internal shared storage

My application will be used offline and I plan daily pull/push synchronizations via USB cable. My users are in a very primitive situation: no wifi, and no cell phone towers. My question is not about synchronization, but rather just getting access to the data so that I can synchronize.
I connect the cable, select USB for file transfer, and I can see Internal Shared Storage. But I cannot find my SqlLite database anywhere. I have tried using these paths for the database:
Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
Android.App.Application.Context.FilesDir.AbsolutePath;
The app works fine with any of those paths, the data is stored and retrieved, but I cannot see the database from my PC.
I have also tried this but it blows up:
Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
I have tried debugging with Xamarin Live but then I get this error:
"You need to call SQLitePCL.raw.SetProvider();"
I have tried adding console.writeline and Log.Error to add in some diagnostics but I can't find any log files in Internal Shared Storage.
I have WRITE_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions in the manifest; even tho I think that is not necessary.
If I could store files in Internal Shared Storage then I could put the database there and access it to synchronize. And I could create a simple text logging facility to write a text log to the same place.
I have rarely asked for help in 40 years but I've been at this for days. Thanks!
To get files onto Internal Shared Storage accessible via USB took 3 steps:
1: Get runtime permissions
ActivityCompat.RequestPermissions(activity, new String[] { Manifest.Permission.WriteExternalStorage, Manifest.Permission.ReadExternalStorage }, 1);
2) use this path:
string extPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
extPath = Path.Combine(extPath, "RtTrace.txt");
File.AppendAllText(extPath, "new content" + System.Environment.NewLine);
3) Media scan the resulting file to make it visible:
MediaScannerConnection.ScanFile(Android.App.Application.Context, new String[] { extPath }, null, null);
The path on Environment.SpecialFolder.Personal refers to a private area where only the app (and the OS itself when you clear data from the app, for example) have access. I don't know about ApplicationData.
You can easily copy your app file (the protected one) to a public folder, like Downloads or create a new folder MyAppDirectory at the public storage space, that will allow access from other devices. Then, you can clear local data that you don't need anymore (after the sync process).
To create a new public folder on Android:
var folder = System.IO.Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, "MyAppDirectory");
System.IO.Directory.CreateDirectory(folder);
You'll get this:
Then, copy the file:
var newFile = Path.Combine(folder, "MySharedFile"); // The database, xml, json, text or any file you want to share
var sourceFullName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),"MyOriginalFile");
System.IO.File.Copy(sourceFullName, newFile, true /* overwrite */);
I hope it helps.
SQLite db is stored in application private memory and can't be accessed over USB, try exporting contents of your DB to an external file in your internal memory or External memory to be able to access it via a USB chord.

Xamarin.Forms Android cannot access USB OTG folder

I'm on an Android 5.0 device where a usb mass storage is mounted at "/storage/usbotg" via USB OTG cable.
Unfortunately from my app I only have read access to that folder. Please note that I set the write external storage permission as I'm able to write to device storage.
I post the following code as reference:
string Root = "/storage/usbotg";
string[] Dirs = Directory.GetDirectories(Root);
string NewFolder = Path.Combine(Root, "NewFolder");
Directory.CreateDirectory(NewFolder);
This gives me an exception on the last line (but I'm able to list subdirectories in Dirs)
Exception:
System.UnauthorizedAccessException
Exception Message:
Access to the path "/storage/usbotg/NewFolder" is denied.
If I use:
string Root = "/storage/emulated/0";
everything is working fine and the "NewFolder" is created.
What I'm missing? How can I write to that folder?
I'm using Xamarin.Forms 2.5.0
Thanks for your help
Accessing data outside your application's private storage using the file system is more restricted with each Android version.
The recommended options are :
Use getExternalFilesDirs(), getExternalCacheDirs, ... : this gives you one or more directories specific to you application (usually directories named after the package name). This does not work for removable media, unless they're adopted.
Use the Storage Access Framework : ask the user (using ACTION_OPEN_DOCUMENT_TREE) to choose the storage root. You can then manage the content of the picked directory through the SAF API. You can persist the permission, so you only need to ask the user once. It seems that it is what ES File explore does to get write permission.
A (much) more detailed explanation by Mark Murphy.

Where is the location of file created by Cordova File Plugin?

I have used Cordova File Plugin to create files on mobile device. Below is the code to create files:
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function (dir) {
alert(cordova.file.dataDirectory);
dir.getFile("log.txt", { create: true }, function (file) {
alert("got the file: "+ file.name + ', ' + file.fullPath);
});
});
When I deploy the app on my android phone, the file will create successfully, but I can't find the created file on my device.
Although cordova.file.dataDirectory is pointing to file:///data/data/io.cordova.myappId/files/ path on my device, the io.cordova.myappId folder doesn't exist in data>data path, but exists in Android>data path. By the way, I checked both storage>Android>data>io.Cordova.myappId>files & storage>data>data and the file doesn't exist.
Is this because:
The created file is located in another place, so where can I find that?
or
Because it's private and my file manager doesn't have access to it, so how can I change the permission setting to have a public file?
Why I can't find the file on my device?
The file is created successfully but I can't find that on my device because the dataDirectory path which I indicates to create the file, is a private path and my device file manager doesn't have access to it (base on this table). Actually dataDirectory is an Internal Storage option.
Internal Storage: Store private data on the device memory.
You can save files directly on the device's internal storage. By
default, files saved to the internal storage are private to your
application and other applications cannot access them (nor can the
user). When the user uninstalls your application, these files are
removed.(reference)
How to create a public file?
So, to create a file on my device that I can access it with the file manager, I have to use one of public path options like:externalDataDirectory. Before, I was thinking it is for storing files on an external SD Card that I had not on my phone, so I didn't test it. But testing it today, it creates the file on my internal device storage in Android/data/<app-id>/files path which is public and I can access it with device file manager.
Actually the term internal and external was misleading for me while external storage can be a removable storage media (such as an SD card) or an internal (non-removable) storage(reference).
Reading/wiring files in Cordova is painful. I wrote a script that uses promises to make this easier.
Add cordova-file-storage.js to your project, then do the following:
// the object you want to save
var objectToSave = { firstName: 'John', lastName: 'Doherty' };
// the filename and extension you want to use
var filename = 'whatever.txt';
// the data to write (convert JSON object to a string)
var data = JSON.stringify(objectToSave);
// call write with params, .then executes with the filePath once complete
fileStorage.write(filename, data).then(function(filePath) {
console.log(filePath);
})
.catch(function(err) {
// this executes if something went wrong
console.warn(err);
});
It uses external storage by default. To use sandboxed storage inaccessible to the user add true as the last param.

How to check if file can be deleted by an android application?

How do I know if a file can be deleted by my android application?
I am writing an android application and a web application that will allow my clients to view and delete their files.
But I will not let the client to view the files that are undeletable.
Like
if(isFileCanBeDeleted("filename.ext"))
{
//save the filename and path to server
}
else
{
//the file is cannot be deleted, this filename will not be saved online
}
You can try by executing shell command,
Runtime.getRuntime().exec("test -e " + "/path/to/file.txt");
However, you need to check API references whether shell runtime is available or not, depending on API Level, or root/non-rooted phone.

Categories

Resources