Xamarin access to external public folder (documents/download) - android

i was using GetExternalStoragePublicDirectory but is deprecated now, it gets back the standard path "/storage/emulated/0/Download" but from Android 12 i can save, load only the file stored from my app, if i add the same file renamed by pc is "filtered" and not accessible, it looks like not present!
i store a txt file from my app, how can i work around to access again to download external public folder?

I have create a sample to test the GetExternalStoragePublicDirectory method and create a txt file in the Download folder. Here is the MainActivity's code:
Button write = this.FindViewById<Button>(Resource.Id.buttonwrite);
Button read = this.FindViewById<Button>(Resource.Id.buttonread);
write.Click += (s, e) =>
{
var path = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads);
var file = Path.Combine(path + "/app.txt");
using (System.IO.FileStream os = new System.IO.FileStream(file, System.IO.FileMode.OpenOrCreate))
{
string temp = "this is test string";
byte[] buffer = Encoding.UTF8.GetBytes(temp);
os.Write(buffer, 0, buffer.Length);
}
Intent intent = new Intent(DownloadManager.ActionViewDownloads);
StartActivity(intent);
// this line code can open the download folder and view all the files in it. When the user click the file, it will be open
};
read.Click += (s, e) =>
{
var path = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDownloads);
var file = Path.Combine(path + "/app.txt");
/* using (System.IO.FileStream os = new System.IO.FileStream(file, System.IO.FileMode.OpenOrCreate))
{
StreamReader streamReader = new StreamReader(os);
var content = streamReader.ReadToEnd();
} */
Intent intent = new Intent(Intent.ActionOpenDocument);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType("text/*");
intent.PutExtra(DocumentsContract.ExtraInitialUri, Uri.Parse(file));
StartActivityForResult(intent, 2);
//This code can open the file picker and let the user to choose a file
};
The app.txt file can still be read when I renamed as New.txt by the file manager. Just change var file = Path.Combine(path + "/app.txt"); to var file = Path.Combine(path + "/New.txt"); and use the code in the /* can read it. So if the file was created by your app, your app can access it even though the file has been renamed by the uesr. But you can access the file in the public folder which was not created by your app.
In addidion, if you don't have to push your app to the google play, you can use the access all file permission according to my old answer in this link and the answer about the deprecated GetExternalStoragePublicDirectory.

Related

How to open my app documents directory with Android File Manager

I've been trying to figure out a way to open the Android File Manager directly in my app's Documents directory so the user can select a JSON file among several without requiring the user to go search for the file path /storage/emulated/0/Android/data/com.company.app/files/Documents/. So far, I can make the "go find it yourself" tactic work, but not the "take the user to the directory for them" approach. Here's what I've tried:
// this is the "go find it yourself" approach that I've used:
String filename = this.getResources().getString(R.string.ExportImportFileNameString);
File directory = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
Uri dirPathUri = Uri.fromFile(directory);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
Intent.createChooser(intent, "Open in...");
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, directory);
startActivityForResult(intent, IMPORT_REQUEST);
When my onActivityComplete handler is called for IMPORT_REQUEST I see the returned data looks like dat=content://com.lge.filemanager.FileProvider/storage/emulated/0/Android/data/com.company.app/files/Documents/SelectedFile.json flg=0x1 }
I've tried to invoke two different combinations of intent.setDataAndType instead of intent.setTypefollowing and that fails to let me select anything:
// This setDataAndType setup does not allow the user to open File Manager, nor navigate to the app Documents:
intent.setDataAndType(dirPath2, "application/json");
// This allows opening of File Manager but returns immediately without allowing the user to select a file, and returns a null data pointer:
intent.setDataAndType(dirPath2, "*/*");
Note that I've tried creating the intent object with ACTION_OPEN_DOCUMENT, ACTION_GET_CONTENT, and ACTION_VIEW with the similar result.
If I only have one file, I know I can have the app simply open a stream reader for a known file name as such:
File directory = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File importFile = new File(directory, filename);
try
{
fis = new FileInputStream (importFile);
InputStreamReader inputStreamReader =
new InputStreamReader(fis, StandardCharsets.UTF_8);
...
However, that doesn't allow me the flexibility that I desire to allow a user to select from multiple files. Can anyone illuminate what's going on here and how to correct the situation.
Based on Commonsware feedback, here's what I have for the solution to this question:
//--------------
// Get the documents location for this app
File directory = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File desiredFilePath = new File(directory.toString());
try{
// read all pathnames for files and directory
File[] allFilesInDirectory = desiredFilePath.listFiles();
// prepare array to place all path strings into
ArrayList<String> filesInDirectoryArray = new ArrayList<String>();
// retrieve each pathname file array
// but someone could simply use the "path" object instead
for(File path:allFilesInDirectory){
if (path != null){
// put all file paths into string array
filesInDirectoryArray.add(path.getPath());
// could discriminate based on file extension, if so desired
}
}
// send file path array for processing
ProcessDocuments(filesInDirectoryArray);
}catch(SecurityException e){
e.printStackTrace();
}

Xamarin Android Sqlite Db browser

I have my first smartphone since one week and try make a App with Xamarin.
I use SQLite with EntityFrameworkCore to store data.
It is work fine, but to debug easier I want use a SQLite browser.
The database file path is 'data/data/{AppName}/Database.db'.
I debug from a physic device by USB, but when I explore the device with Windows Explorer I cannot find the SQLite DB file. The 'data/data' folder is not available. Then I can not use a SQLite browser to see the data.
In this post, the author use a Android emulator and can see 'data/data' folder :
https://blog.xamarin.com/building-android-apps-with-entity-framework/
But I prefer use a real device.
Have you a solution?
A solution from the MikeT, in development store the db file in available folder like this :
public static string DatabasePath
{
get
{
var dbFolder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
var fileName = "database.db";
var dbFullPath = Path.Combine(dbFolder, fileName);
return dbFullPath;
}
}
In production, copy the db file to a available folder.
One a real device you would, I believe, need to root the device to directly access the data.
However, what you could do is to copy the database file elsewhere e.g. to external storage. In following is the core process that I use:-
try {
FileInputStream fis = new FileInputStream(dbfile);
OutputStream backup = new FileOutputStream(backupfilename);
//byte[] buffer = new byte[32768];
int length;
while((length = fis.read(buffer)) > 0) {
backup.write(buffer, 0, length);
}
backup.flush();
backup.close();
fis.close();
catch (IOException e) {
e.printStackTrace();
confirmaction = false;
}
I use the following to get the pathname for backupfilename:-
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),subdirectory);
this.directory = dir.getPath();
I then add the actual filename (which is user input).
Note! I do checks to determine that EXTERNAL storage is mounted etc.
To get the database path i use:-
String dbfilename = this.getDatabasePath(
DBConstants.DATABASE_NAME).getPath();
dbfile = new File(dbfilename);
This is of course Java, but I'd assume that it could be converted/adapted to suit. The crux of the answer is to get the database file into a place from which you can access it.
Call the ExtractDb method from your activity
public void ExtractDB()
{
var szSqliteFilename = "databasename.db3";
var szSourcePath = new FileManager().GetLocalFilePath(szSqliteFilename);
var szDatabaseBackupPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/databasename_Backup.db3";
if (File.Exists(szSourcePath))
{
File.Copy(szSourcePath, szDatabaseBackupPath, true);
Toast.MakeText(this, "Copied", ToastLength.Short).Show();
}
}
Get path to the android device storage as shown below
public class FileManager
{
public string GetLocalFilePath(string filename)
{
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return Path.Combine(path, filename);
}
}
you need to add the android.permission.WRITE_EXTERNAL_STORAGE permission in your manifest file.

Unable to create file in Android app

I am making a android app in which i am going to use File handling but to do that first i need to create it but by using following code:
File logf = new File("log1.txt");
Boolean bb = logf.exists();
if(!bb)
try {
bb = logf.createNewFile();
} catch (IOException e) {
msg.setText("not able to create file.");
}
'msg' is the TextView object which i am using to display error, and when i run this app.. it goes into IOException e catch.. Please tell me if i am doing something wrong or what?.. besides i am using Android 2.2 for my app.
In app storage, please try this:
File file = new File(getFilesDir(), "file.txt");
Or if you want to append file name, try this:
File file = new File(getFilesDir() + File.separator + "file.txt");
you need to provide absolute path of file like below.
File file = new File(/data/packagename/files/ + "log1.txt");

Storage in android studio

I am trying to pull multiple images from gallery and place in grid view , Unfortunately I am not able to do so, Can you help me with that. And also I made a folder in sd card and I m trying to store audio as well as photographs in the same folder. Can you help me with that as well?
I am using android 2.3.
So I have included this code inside the button click but on click of button it has created the folder but its not storing the file inside the folder. On click of the button every other thing is working, its opening the gallery and its calculating numpic. I am not sure why its not storing the file in CN Video folder.
public void onClick(View v) {
Intent pass_data = new Intent(MainRecord.this, OpenGallery.class);
pass_data.putExtra("numpic",numpic);
startActivity(pass_data);
// Saving Audio recorded file to directory
File f = new File(Environment.getExternalStorageDirectory() + "/CNvideo");
if(f.isDirectory()) {
//Write code for the folder exist condition
}else {
// create a File object for the parent directory
File CNvideoDirectory = new File("/sdcard/CNVideo/");
// have the object build the directory structure, if needed.
CNvideoDirectory.mkdirs();
// create a File object for the output file
String filename = getfilename();
File outputFile = new File(CNvideoDirectory, filename);
// now attach the OutputStream to the file object, instead of a String representation
try {
FileOutputStream fos = new FileOutputStream(outputFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}};

Can not play video from my internal application directory

It looks like I can not play videos stored in my internal application directory.
I have videos stored in /data/data/my.package.org/files/
And I'm trying to play a file from there using
String fpath = "/data/data/my.package.org/files/video.mpg"
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(fpath), "video/*");
But both Android default video player and some external videoplayer (MX player) say 'this video can not be played".
Whereas when I'm saving videos to SD card they are played fine.
Why is that?
Put your video in assets folder and use this code to play video with MediaPlayer
InputStream is = getResources().getAssets().open("video.mpg");
OR
Put your video in assets folder and...
String fpath = "/data/data/my.package.org/assets/video.mpg"
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(fpath), "video/*");
put your video in the res\raw folder. Then copy it out to the external directories where apps like video player can read them. Only your app can read /data/data/blah....
if its in res\raw, then
typeName = sourceSink.Types.video.toString();
for (sourceSink.VideoFiles video: sourceSink.VideoFiles.values() ){
resourceName = video.toString();
fileName = resourceName + ".mp4";
resource = getResources().getIdentifier(resourceName, "raw", "com.invodo.allshareplay");
createExternalStoragePublicFile(typeName,fileName,resource);
}
and then you can use this to copy it:
void createExternalStoragePublicFile(String fType, String fname, int res ) {
// Create a path where we will place our picture in the user's
// public pictures directory. Note that you should be careful about
// what you place here, since the user often manages these files. For
// pictures and other media owned by the application, consider
// Context.getExternalMediaDir().
File path = null;
if (((fType.equals(sourceSink.Types.photo.toString())) || (fType.equals(sourceSink.Types.file.toString())) ) ){
path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
}
if (fType.equals(sourceSink.Types.music.toString())) {
path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MUSIC);
}
if (fType.equals(sourceSink.Types.video.toString())) {
path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES);
}
File file = new File(path, "/" + fname);
try {
// Make sure the Pictures directory exists.
path.mkdirs();
// Very simple code to copy a picture from the application's
// resource into the external file. Note that this code does
// no error checking, and assumes the picture is small (does not
// try to copy it in chunks). Note that if external storage is
// not currently mounted this will silently fail.
InputStream is = getResources().openRawResource(res);
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
scanMedia(file);
} catch (IOException e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing " + file, e);
}
}
then it's easy - just do the second half of the answer I provided and write them out. /data/data/ folder is never going to be viewed by anything other than your app.

Categories

Resources