unit Unit1;

interface

uses
  System.Messaging,
  {$IF DEFINED(ANDROID) AND (RTLVersion >= 33)}
  Androidapi.JNI.Os,
  System.Permissions,
  {$ENDIF}
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo;

type
  TForm1 = class(TForm)
    mmo1: TMemo;
    btn1: TButton;
    btn2: TButton;
    btn3: TButton;
    btn4: TButton;
    chkAllowMultiSelect: TCheckBox;
    procedure btn2Click(Sender: TObject);
    procedure btn1Click(Sender: TObject);
    procedure btn3Click(Sender: TObject);
    procedure btn4Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
    {$IF DEFINED(ANDROID) AND (RTLVersion >= 33)}
    procedure PermissionsCheck;
    procedure PermissionsResultHandler(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
    {$ENDIF}
    procedure DoReceivedImagePath(const Sender: TObject; const M: TMessage);
    procedure DoCancelReceivingImage(const Sender: TObject; const M: TMessage);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses
  {$IFDEF ANDROID}
  Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.Provider,
  Androidapi.JNI.JavaTypes, Androidapi.JNI.App, Androidapi.JNI.Net,
  Androidapi.Helpers, ksAndroid.Helpers,
  FMX.Platform.Android,
  {$ENDIF}
  FMX.Platform;

type
  TOpenFileCallback = reference to procedure(const ACode: Integer; const APath: string; const APathes: TStrings);
  TOpenFileEvent = procedure (const ACode: Integer; const APath: string; const APathes: TStrings) of object;

const
  FILE_SELECT_CODE = 0;
var
  FOpenFileMessageID: Integer = 0;
  FOpenFileCallback: TOpenFileCallback = nil;
  FOpenFileEvent: TOpenFileEvent = nil;
  FOpenFileAction: JString = nil;

// https://stackoverflow.com/questions/31002388/android-intent-extra-allow-multiple-allows-only-single-picking
procedure HandleActivityMessage(const Sender: TObject; const M: TMessage);
var
  I: Integer;
  LCode: Integer;
  FileName:string;
  LURI: Jnet_Uri;
  LClipData: JClipData;
  LList: TStringList;
begin
  if (not Assigned(M)) or (not (M is TMessageResultNotification))
    or (TMessageResultNotification(M).RequestCode <> FILE_SELECT_CODE) then
    Exit;

  LCode := TMessageResultNotification(M).ResultCode;
  FileName := '';
  LList := nil;

  {$IFDEF DEBUG}
  if LCode = TJActivity.JavaClass.RESULT_CANCELED then
    Log.d('---HandleActivityMessage-RESULT_CANCELED');
  if LCode = TJActivity.JavaClass.RESULT_FIRST_USER then
    Log.d('---HandleActivityMessage-RESULT_FIRST_USER');
  {$ENDIF}

  if LCode = TJActivity.JavaClass.RESULT_OK then begin
    if TMessageResultNotification(M).Value <> nil then begin
      with TMessageResultNotification(M).Value do begin
        LURI := getData;
        if LURI <> nil then
          FileName := TAndroidHelperEx.FileFromUri(LURI)
        else begin
          LClipData := getClipData;
          if LClipData <> nil then begin
            LList := TStringList.Create;
            for I := 0 to LClipData.getItemCount - 1 do begin
              LURI := LClipData.getItemAt(I).getUri;
              if LURI <> nil then
                LList.Add(TAndroidHelperEx.FileFromUri(LURI))
              {$IFDEF DEBUG}
              else
                Log.d('---HandleActivityMessage-getClipData.getItemAt(%d).getUri:nil', [I]);
              {$ENDIF}
            end;
          end
          {$IFDEF DEBUG}
          else
            Log.d('---HandleActivityMessage-getData & getClipData:nil');
          {$ENDIF}
        end;
      end;
    end
    else begin
      {$IFDEF DEBUG}
      Log.d('---HandleActivityMessage-Value:nil');
      {$ENDIF}
    end;
  end;

  {$IFDEF DEBUG}
  Log.d('---HandleActivityMessage-ResultCode:%d-', [LCode]);
  {$ENDIF}

  if Assigned(FOpenFileCallback) then
    FOpenFileCallback(LCode, FileName, LList);
  if Assigned(FOpenFileEvent) then
    FOpenFileEvent(LCode, FileName, LList);

  if Assigned(LList) then
    FreeAndNil(LList);

  if FOpenFileMessageID <> 0 then begin
    TMessageManager.DefaultManager.Unsubscribe(TMessageResultNotification, FOpenFileMessageID);
    FOpenFileMessageID := 0;
    FOpenFileCallback := nil;
    FOpenFileEvent := nil;
  end;
end;

function OpenFileDialog(AOpenFileCallback: TOpenFileCallback; AOpenFileEvent: TOpenFileEvent;
  AExt, ADir: string; AData: Jnet_Uri; AAllowMultiSelect: Boolean): Boolean;
var
  LIntent: JIntent;
  LType: string;
begin
  Result := False;
  LType := '';

  if (LType = '') or (AExt  = '*.*') or (AExt = '*') then
    LType := ''
  else if Pos('/', AExt) > 0 then
    LType := AExt
  else
    LType := JStringToString(TAndroidHelperEx.GetMimeType(AExt));

  if LType = '' then
    LType := '*/*';

  if FOpenFileAction = nil then //Ĭ��ֵ
    FOpenFileAction := TJIntent.JavaClass.ACTION_GET_CONTENT;

  LIntent := TJIntent.JavaClass.init(FOpenFileAction);
  LIntent.setType(StringToJString(LType));

  if AAllowMultiSelect then
    LIntent.putExtra(TJIntent.JavaClass.EXTRA_ALLOW_MULTIPLE, true);

  if not FOpenFileAction.equals(TJIntent.JavaClass.ACTION_PICK) then
    LIntent.addCategory(TJIntent.JavaClass.CATEGORY_OPENABLE);

  if AData <> nil then
    LIntent.setData(AData)
  else if ADir <> '' then
    LIntent.setData(TAndroidHelperEx.UriParse(ADir));

  if FOpenFileMessageID = 0 then begin
    FOpenFileMessageID := TMessageManager.DefaultManager.SubscribeToMessage(TMessageResultNotification, HandleActivityMessage);
    FOpenFileCallback := AOpenFileCallback;
    FOpenFileEvent := AOpenFileEvent;
  end;

  try
    try
      //Result := TAndroidHelperEx.StartActivity(TJIntent.JavaClass.createChooser(Intent, StrToJCharSequence(ATitle)), FILE_SELECT_CODE)
      Result := TAndroidHelperEx.StartActivity(LIntent, FILE_SELECT_CODE);
    except
      raise Exception.Create('File Manager not found');
    end;
  finally
    Form1.mmo1.Lines.Add(Format('OpenFileDialog:%s', [BoolToStr(Result, True)]));
  end;
end;

procedure TForm1.btn1Click(Sender: TObject);
begin
  //Intent.setData(TJImages_Media.JavaClass.EXTERNAL_CONTENT_URI) // ������������޶�APP������������� ͼ��
  //Intent.setData(TJContactsContract_Contacts.JavaClass.CONTENT_URI) // ��ϵ�ˣ���ָ������Ļ���ֱ��ȡ��
  FOpenFileAction := TJIntent.JavaClass.ACTION_PICK;
  OpenFileDialog(procedure(const ACode: Integer; const APath: string; const APathes: TStrings) begin
      if APath <> '' then
        mmo1.Lines.Add(APath)
      else if Assigned(APathes) then
        mmo1.Lines.AddStrings(APathes)
      else
        mmo1.Lines.Add(Format('Error code: %d', [ACode]));
    end,
    nil, '*/*', '', TJImages_Media.JavaClass.EXTERNAL_CONTENT_URI, chkAllowMultiSelect.IsChecked
  )
end;

procedure TForm1.btn2Click(Sender: TObject);
begin
  FOpenFileAction := TJIntent.JavaClass.ACTION_GET_CONTENT;
  OpenFileDialog(procedure(const ACode: Integer; const APath: string; const APathes: TStrings) begin
      if APath <> '' then
        mmo1.Lines.Add(APath)
      else if Assigned(APathes) then
        mmo1.Lines.AddStrings(APathes)
      else
        mmo1.Lines.Add(Format('Error code: %d', [ACode]));
    end,
    nil, '*/*', '', nil, chkAllowMultiSelect.IsChecked
  )
end;

procedure TForm1.btn3Click(Sender: TObject);
begin
  FOpenFileAction := TJIntent.JavaClass.ACTION_OPEN_DOCUMENT;
  OpenFileDialog(procedure(const ACode: Integer; const APath: string; const APathes: TStrings) begin
      if APath <> '' then
        mmo1.Lines.Add(APath)
      else if Assigned(APathes) then
        mmo1.Lines.AddStrings(APathes)
      else
        mmo1.Lines.Add(Format('Error code: %d', [ACode]));
    end,
    nil, '*/*', '', nil, chkAllowMultiSelect.IsChecked
  )
end;

procedure TForm1.btn4Click(Sender: TObject);
var
  FSize: TSize;
begin
  FSize.cx := TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize);
  FSize.cy := TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize);
  MainActivity.getFMXMediaLibrary.takeImageFromLibrary(FSize.Width, FSize.Height, False);
end;

procedure TForm1.DoCancelReceivingImage(const Sender: TObject; const M: TMessage);
begin
  if (M is TMessageCancelReceivingImage) then
    mmo1.Lines.Add('TMessageCancelReceivingImage');
end;

procedure TForm1.DoReceivedImagePath(const Sender: TObject; const M: TMessage);
begin
  if (M is TMessageReceivedImagePath) then
    mmo1.Lines.Add(Format('TMessageReceivedImagePath: %s', [(M as TMessageReceivedImagePath).Value]));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMessageManager.DefaultManager.SubscribeToMessage(TMessageCancelReceivingImage, DoCancelReceivingImage);
  TMessageManager.DefaultManager.SubscribeToMessage(TMessageReceivedImagePath, DoReceivedImagePath);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  TMessageManager.DefaultManager.Unsubscribe(TMessageReceivedImagePath, DoReceivedImagePath);
  TMessageManager.DefaultManager.Unsubscribe(TMessageCancelReceivingImage, DoCancelReceivingImage);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  {$IF DEFINED(ANDROID) AND (RTLVersion >= 33)}
  PermissionsCheck;
  {$ENDIF}
end;

{$IF DEFINED(ANDROID) AND (RTLVersion >= 33)}
procedure TForm1.PermissionsCheck;
begin
  if TJBuild_VERSION.JavaClass.SDK_INT >= 23 then
    PermissionsService.RequestPermissions([JStringToString(TJManifest_permission.JavaClass.CAMERA),
       JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
       JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)], PermissionsResultHandler);
end;

procedure TForm1.PermissionsResultHandler(const APermissions: TArray<string>;
  const AGrantResults: TArray<TPermissionStatus>);
begin
  if PermissionsService.IsEveryPermissionGranted(
    [JStringToString(TJManifest_permission.JavaClass.CAMERA),
     JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
     JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)]) then
    mmo1.Lines.Add('Permission granted')
  else
    mmo1.Lines.Add('Permission not granted');
end;
{$ENDIF}

end.