3

This is probably super simple but I'm having trouble reading bytes from a file. I have it working fine with iOS but with Android it always crashes with a DirectoryNotFoundException. So I think the uri is wrong but I'm not sure where I'm wrong with it...

My view has a button that opens up a file picker...

var selectedDocumentPath = await DependencyService.Get<IFilePicker>().pickDocument();

My FilePicker class...

class FilePicker : IFilePicker
{
    public async Task<string> pickDocument()
    {
        string fileUri = string.Empty; 
        Console.WriteLine("Selecting Document from android device.");
        Intent intent = new Intent(Intent.ActionOpenDocument);
        intent.SetType("*/*");
        intent.PutExtra(Intent.ExtraMimeTypes, new string[] { "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" });
        intent.AddCategory(Intent.CategoryOpenable);

        ((Activity)Forms.Context).StartActivityForResult(Intent.CreateChooser(intent, "Select Document"), MainActivity.DOCUMENT_CODE);

        return await GetDocumentPath(new CancellationTokenSource());
    }

    private async Task<string> GetDocumentPath(CancellationTokenSource TokenSource)
    {
        var path = string.Empty;
        var LoopCheck = true;
        while (LoopCheck)
        {
            for (var i = 0; i < 100; i++)
            {
                if (MainActivity.fileUri != null || MainActivity.cancelled) { LoopCheck = false; TokenSource.Cancel(); }
                try { await Task.Delay(1000, TokenSource.Token); }
                catch (TaskCanceledException) { break; }
            }
        }
        if (!MainActivity.cancelled)
        {
            path = MainActivity.fileUri.OriginalString;
        }
        MainActivity.fileUri = null;
        MainActivity.cancelled = false;

        return path; 
    }
}

The OnActivityResult method located in MainActivity.cs....

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
     base.OnActivityResult(requestCode, resultCode, data);

     if (resultCode == Result.Ok && requestCode == DOCUMENT_CODE) { fileUri = new Uri(data.Data.Path); }
     else if(resultCode == Result.Canceled) { cancelled = true; }
}

Some paths that I'm getting...

data.DataString = content://com.android.externalstorage.documents/document/primary%3ADownload%2FSampleResume%20(1).docx

data.Data.SchemeSpecificPart = //com.android.externalstorage.documents/document/primary:Download/SampleResume (1).docx

data.Data.Path = /document/primary:Download/SampleResume (1).docx

and then some encoded options as well. But all of these give me an error later on when I try and read it using ...

File.ReadAllBytes(selectedDocumentPath); 

EDIT: I've replaced fileUri = new Uri(data.Data.Path); with

var uri = DocumentsContract.BuildDocumentUri(data.Data.Authority,
                DocumentsContract.GetDocumentId(data.Data));                
fileUri = new Uri(uri.Path); 

But still come out with the same type of path like /document/primary:Download/SampleResume (1).docx

John
  • 1,808
  • 7
  • 28
  • 57
  • 1
    Possible duplicate of [howto get the real path with ACTION\_OPEN\_DOCUMENT\_TREE Intent. Lollipop API 21 & 22](http://stackoverflow.com/questions/29713587/howto-get-the-real-path-with-action-open-document-tree-intent-lollipop-api-21) – Jason Jul 25 '16 at 19:12

1 Answers1

1

I found the solution at: https://codereview.stackexchange.com/questions/182082/reading-file-from-flash-with-xamarin-forms-on-android-using-actionopendocument-i

Basically, from Intent.Data (if you receive the file this way), or from any Android.Net.Uri that is type content, for example: content://com.android.providers.downloads.documents/document/13

You should do the following to read the file:

using (var parcelFileDescriptor = ContentResolver.OpenFileDescriptor(Intent.Data, "r"))
using (Java.IO.FileDescriptor fileDescriptor = parcelFileDescriptor.FileDescriptor)
using (var reader = new Java.IO.FileReader(fileDescriptor))
using (var bufferedReader = new Java.IO.BufferedReader(reader))
{
    string line;
    while ((line = bufferedReader.ReadLine()) != null)
    {
        if (line != null)
        {

        }
    }
}
Jonwd
  • 635
  • 10
  • 24