I'm using this code to access files on Android via content uri as TStream:
stream := TipJavaContentResolverStream.Create(uri);
Tested on Delphi 11, TipJavaContentResolverStream work with files openned as ParcelFileDescriptor.AutoCloseInputStream, i don't know TJIntent.JavaClass.ACTION_OPEN_DOCUMENT use this model or not, try it:
{
The module contains a class for retrieving data from ContentResolver as TStream
Author: Victor Fedorenkov
}
unit ipJavaContentResolverStreamUnit.Android;
interface
uses
SysUtils, Types,
Androidapi.JNI.Net,
Androidapi.Jni.Os,
Androidapi.Helpers,
Androidapi.JNIBridge,
Androidapi.JNI.JavaTypes,
ipJavaFileInputStreamUnit.Android;
type
TipJavaContentResolverStream = class(TipJavaFileInputStream)
private
FContentUri: string;
public
constructor Create(const AContentUri: string);
end;
implementation
const
JParcelFileDescriptor_AutoCloseInputStream_ClassName = 'android.os.ParcelFileDescriptor$AutoCloseInputStream';
{ TipJavaContentResolverStream }
constructor TipJavaContentResolverStream.Create(const AContentUri: string);
var
JUri: Jnet_Uri;
JStream: JInputStream;
ContentStreamClassName: string;
begin
FContentUri := AContentUri;
JUri := TJnet_Uri.JavaClass.parse(StringToJString(AContentUri));
JStream := TAndroidHelper.Context.getContentResolver.openInputStream(JUri);
if not Assigned(JStream) then
raise Exception.Create('Unable get content stream: ' + AContentUri);
ContentStreamClassName := JStringToString(JStream.getClass.getName);
if ContentStreamClassName <> JParcelFileDescriptor_AutoCloseInputStream_ClassName then
raise Exception.CreateFmt('Can''t open content class %s from %s', [
ContentStreamClassName, AContentUri]);
inherited Create(TJParcelFileDescriptor_AutoCloseInputStream.Wrap((JStream as ILocalObject).GetObjectID));
end;
end.
{
Adapter for reading JFileInputStream as a regular TStream
Author: Victor Fedorenkov
}
unit ipJavaFileInputStreamUnit.Android;
interface
uses
SysUtils, Classes, Math, RTLConsts,
Androidapi.Jni,
Androidapi.JNIBridge,
Androidapi.JNI.JavaTypes;
type
TipJavaFileInputStream = class(TStream)
private
FJStream: JFileInputStream;
protected
function GetSize: Int64; override;
public
constructor Create(AJStream: JFileInputStream);
function Read(var Buffer; Count: LongInt): LongInt; override;
function Write(const Buffer; Count: LongInt): LongInt; override;
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
property JStream: JFileInputStream read FJStream;
end;
implementation
{ TipJavaFileInputStream }
constructor TipJavaFileInputStream.Create(AJStream: JFileInputStream);
begin
FJStream := AJStream;
end;
function TipJavaFileInputStream.GetSize: Int64;
begin
Result := FJStream.getChannel.size;
end;
function TipJavaFileInputStream.Write(const Buffer; Count: LongInt): LongInt;
begin
raise EStreamError.CreateRes(@SWriteError);
end;
function TipJavaFileInputStream.Read(var Buffer; Count: LongInt): LongInt;
var
CanRead: LongInt;
ReadRes: Integer;
b: TJavaArray<Byte>;
begin
Result := 0;
b := nil;
try
repeat
// Calculate how much we can read from the current position
CanRead := Min(FJStream.available, Count - Result);
// Allocate a buffer for reading if it doesn't exist or is not large enough
if (not Assigned(b)) or (b.Length < CanRead) then
begin
FreeAndNil(b);
b := TJavaArray<Byte>.Create(CanRead);
end;
// Read the data
ReadRes := FJStream.read(b, 0, CanRead);
// Copy what was successfully read into the buffer
if ReadRes > 0 then
begin
Move(b.Data^, (PByte(@Buffer) + Result)^, ReadRes);
Inc(Result, ReadRes);
end;
// Continue reading until there is nothing left to read
until ReadRes <= 0;
finally
FreeAndNil(b);
end;
end;
function TipJavaFileInputStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
var
NewPosition: Int64;
begin
// To avoid a warning
NewPosition := 0;
case Origin of
soBeginning: NewPosition := Offset;
soCurrent: NewPosition := FJStream.getChannel.position + Offset;
soEnd: NewPosition := Size + Offset;
end;
Result := FJStream.getChannel.position(NewPosition).position;
end;
end.