From 85c2b14e461cd4fa630bb6331d671d3321b3398e Mon Sep 17 00:00:00 2001 From: aBit Systems Date: Fri, 24 May 2019 13:18:48 +0800 Subject: [PATCH 1/2] Removal of Form Requirement for creating an instance - The owner will be used or Application.MainForm - Windows Handler --- Source/UExternalFileViewer.pas | 97 ++++++---- .../Windows/UExternalFileViewer.Windows.pas | 58 ++++++ Source/iOS/UExternalFileViewer.iOS.pas | 182 ++++++++++-------- 3 files changed, 220 insertions(+), 117 deletions(-) create mode 100644 Source/Windows/UExternalFileViewer.Windows.pas diff --git a/Source/UExternalFileViewer.pas b/Source/UExternalFileViewer.pas index 449681a..3e5cdd3 100644 --- a/Source/UExternalFileViewer.pas +++ b/Source/UExternalFileViewer.pas @@ -1,21 +1,21 @@ -{****************************************************} -{ } -{ firemonkey-external-file-viewer } -{ } -{ Copyright (C) 2018 Code Partners Pty Ltd } -{ } -{ http://www.code-partners.com } -{ } -{****************************************************} -{ } -{ This Source Code Form is subject to the terms of } -{ the Mozilla Public License, v. 2.0. If a copy of } -{ the MPL was not distributed with this file, You } -{ can obtain one at } -{ } -{ http://mozilla.org/MPL/2.0/ } -{ } -{****************************************************} +{ **************************************************** } +{ } +{ firemonkey-external-file-viewer } +{ } +{ Copyright (C) 2018 Code Partners Pty Ltd } +{ } +{ http://www.code-partners.com } +{ } +{ **************************************************** } +{ } +{ This Source Code Form is subject to the terms of } +{ the Mozilla Public License, v. 2.0. If a copy of } +{ the MPL was not distributed with this file, You } +{ can obtain one at } +{ } +{ http://mozilla.org/MPL/2.0/ } +{ } +{ **************************************************** } unit UExternalFileViewer; interface @@ -24,19 +24,19 @@ interface System.SysUtils, System.Classes, FMX.Forms; type - TExternalFileViewer = class (TComponent) + TExternalFileViewer = class(TComponent) protected - FForm: TForm; + FForm: TCommonCustomForm; - constructor Create(AOwner: TComponent; AForm: TForm); reintroduce; virtual; + constructor Create(AOwner: TComponent); reintroduce; virtual; public - class function Factory(AOwner: TComponent; AForm: TForm): TExternalFileViewer; + class function Factory(AOwner: TComponent): TExternalFileViewer; procedure OpenFile(Path: string); virtual; abstract; procedure OpenURL(URL: string); virtual; abstract; end; - TDummyExternalFileViewer = class (TExternalFileViewer) + TDummyExternalFileViewer = class(TExternalFileViewer) public procedure OpenFile(Path: string); override; procedure OpenURL(URL: string); override; @@ -44,32 +44,47 @@ TDummyExternalFileViewer = class (TExternalFileViewer) implementation - {$IF DEFINED(ANDROID)} - uses - UExternalFileViewer.Android; - {$ELSEIF DEFINED(IOS)} - uses - UExternalFileViewer.iOS; - {$ENDIF} +{$IF DEFINED(ANDROID)} +uses + UExternalFileViewer.Android; +{$ELSEIF DEFINED(IOS)} + +uses + UExternalFileViewer.iOS; +{$ELSEIF DEFINED(MSWINDOWS)} + +uses + UExternalFileViewer.Windows; +{$ENDIF} { TExternalFileViewer } -constructor TExternalFileViewer.Create(AOwner: TComponent; AForm: TForm); +constructor TExternalFileViewer.Create(AOwner: TComponent); begin inherited Create(AOwner); - self.FForm := AForm; + if (AOwner is TCommonCustomForm) then + begin + self.FForm := (AOwner as TCommonCustomForm) + end + else + begin + self.FForm := Application.MainForm; + end; + end; -class function TExternalFileViewer.Factory(AOwner: TComponent; - AForm: TForm): TExternalFileViewer; +class function TExternalFileViewer.Factory(AOwner: TComponent) + : TExternalFileViewer; begin - {$IF DEFINED(ANDROID)} - Result := TAndroidExternalFileViewer.Create(AOwner, AForm); - {$ELSEIF DEFINED(IOS)} - Result := TiOSExternalFileViewer.Create(AOwner, AForm); - {$ELSE} - Result := TDummyExternalFileViewer.Create(AOwner, AForm); - {$ENDIF} +{$IF DEFINED(MSWINDOWS)} + Result := TWindowsExternalFileViewer.Create(AOwner); +{$ELSEIF DEFINED(ANDROID)} + Result := TAndroidExternalFileViewer.Create(AOwner); +{$ELSEIF DEFINED(IOS)} + Result := TiOSExternalFileViewer.Create(AOwner); +{$ELSE} + Result := TDummyExternalFileViewer.Create(AOwner); +{$ENDIF} end; { TDummyExternalFileViewer } diff --git a/Source/Windows/UExternalFileViewer.Windows.pas b/Source/Windows/UExternalFileViewer.Windows.pas new file mode 100644 index 0000000..0f18348 --- /dev/null +++ b/Source/Windows/UExternalFileViewer.Windows.pas @@ -0,0 +1,58 @@ +{ **************************************************** } +{ } +{ firemonkey-external-file-viewer } +{ } +{ Copyright (C) 2018 Code Partners Pty Ltd } +{ } +{ http://www.code-partners.com } +{ } +{ **************************************************** } +{ } +{ This Source Code Form is subject to the terms of } +{ the Mozilla Public License, v. 2.0. If a copy of } +{ the MPL was not distributed with this file, You } +{ can obtain one at } +{ } +{ http://mozilla.org/MPL/2.0/ } +{ } +{ **************************************************** } +unit UExternalFileViewer.Windows; + +interface + +{$IFDEF MSWINDOWS} + +uses + System.SysUtils, System.Classes, UExternalFileViewer, + System.IOUtils; + +type + TWindowsExternalFileViewer = class(TExternalFileViewer) + private + public + procedure OpenFile(Path: string); override; + procedure OpenURL(URL: string); override; + end; + +{$ENDIF} + +implementation + +{$IFDEF MSWINDOWS} + +uses + Winapi.ShellAPI, Winapi.Windows; + +procedure TWindowsExternalFileViewer.OpenFile(Path: string); +begin + ShellExecute(0, 'OPEN', PChar(Path), '', '', SW_SHOWNORMAL); +end; + +procedure TWindowsExternalFileViewer.OpenURL(URL: string); +begin + ShellExecute(0, 'OPEN', PChar(URL), '', '', SW_SHOWNORMAL); +end; + +{$ENDIF} + +end. diff --git a/Source/iOS/UExternalFileViewer.iOS.pas b/Source/iOS/UExternalFileViewer.iOS.pas index ff13ecb..94e0572 100644 --- a/Source/iOS/UExternalFileViewer.iOS.pas +++ b/Source/iOS/UExternalFileViewer.iOS.pas @@ -1,21 +1,21 @@ -{****************************************************} -{ } -{ firemonkey-external-file-viewer } -{ } -{ Copyright (C) 2018 Code Partners Pty Ltd } -{ } -{ http://www.code-partners.com } -{ } -{****************************************************} -{ } -{ This Source Code Form is subject to the terms of } -{ the Mozilla Public License, v. 2.0. If a copy of } -{ the MPL was not distributed with this file, You } -{ can obtain one at } -{ } -{ http://mozilla.org/MPL/2.0/ } -{ } -{****************************************************} +{ **************************************************** } +{ } +{ firemonkey-external-file-viewer } +{ } +{ Copyright (C) 2018 Code Partners Pty Ltd } +{ } +{ http://www.code-partners.com } +{ } +{ **************************************************** } +{ } +{ This Source Code Form is subject to the terms of } +{ the Mozilla Public License, v. 2.0. If a copy of } +{ the MPL was not distributed with this file, You } +{ can obtain one at } +{ } +{ http://mozilla.org/MPL/2.0/ } +{ } +{ **************************************************** } unit UExternalFileViewer.iOS; interface @@ -23,7 +23,7 @@ interface {$IFDEF IOS} uses - System.SysUtils, System.Classes, FMX.Forms, UExternalFileViewer, + System.SysUtils, System.Classes, FMX.Types, FMX.Forms, UExternalFileViewer, Macapi.Helpers, iOSAPI.Foundation, iOSAPI.Helpers, @@ -38,42 +38,56 @@ interface type TiOSExternalFileViewer = class; - TUIDocumentInteractionControllerDelegate = class(TOCLocal, UIDocumentInteractionControllerDelegate) + TUIDocumentInteractionControllerDelegate = class(TOCLocal, + UIDocumentInteractionControllerDelegate) private - [Weak] FViewer: TiOSExternalFileViewer; + [Weak] + FViewer: TiOSExternalFileViewer; public constructor Create(AViewer: TiOSExternalFileViewer); - function documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) - : UIViewController; cdecl; - function documentInteractionControllerRectForPreview(controller: UIDocumentInteractionController): CGRect; cdecl; - function documentInteractionControllerViewForPreview(controller: UIDocumentInteractionController): UIView; cdecl; - procedure documentInteractionControllerWillBeginPreview(controller: UIDocumentInteractionController); cdecl; - procedure documentInteractionControllerDidEndPreview(controller: UIDocumentInteractionController); cdecl; - procedure documentInteractionControllerWillPresentOptionsMenu(controller: UIDocumentInteractionController); cdecl; - procedure documentInteractionControllerDidDismissOptionsMenu(controller: UIDocumentInteractionController); cdecl; - procedure documentInteractionControllerWillPresentOpenInMenu(controller: UIDocumentInteractionController); cdecl; - procedure documentInteractionControllerDidDismissOpenInMenu(controller: UIDocumentInteractionController); cdecl; + function documentInteractionControllerViewControllerForPreview + (controller: UIDocumentInteractionController): UIViewController; cdecl; + function documentInteractionControllerRectForPreview + (controller: UIDocumentInteractionController): CGRect; cdecl; + function documentInteractionControllerViewForPreview + (controller: UIDocumentInteractionController): UIView; cdecl; + procedure documentInteractionControllerWillBeginPreview + (controller: UIDocumentInteractionController); cdecl; + procedure documentInteractionControllerDidEndPreview + (controller: UIDocumentInteractionController); cdecl; + procedure documentInteractionControllerWillPresentOptionsMenu + (controller: UIDocumentInteractionController); cdecl; + procedure documentInteractionControllerDidDismissOptionsMenu + (controller: UIDocumentInteractionController); cdecl; + procedure documentInteractionControllerWillPresentOpenInMenu + (controller: UIDocumentInteractionController); cdecl; + procedure documentInteractionControllerDidDismissOpenInMenu + (controller: UIDocumentInteractionController); cdecl; [MethodName('documentInteractionController:willBeginSendingToApplication:')] - procedure documentInteractionControllerWillBeginSendingToApplication(controller: UIDocumentInteractionController; + procedure documentInteractionControllerWillBeginSendingToApplication + (controller: UIDocumentInteractionController; willBeginSendingToApplication: NSString); cdecl; [MethodName('documentInteractionController:didEndSendingToApplication:')] - procedure documentInteractionControllerDidEndSendingToApplication(controller: UIDocumentInteractionController; + procedure documentInteractionControllerDidEndSendingToApplication + (controller: UIDocumentInteractionController; didEndSendingToApplication: NSString); cdecl; [MethodName('documentInteractionController:canPerformAction:')] - function documentInteractionControllerCanPerformAction(controller: UIDocumentInteractionController; - canPerformAction: SEL): Boolean; cdecl; + function documentInteractionControllerCanPerformAction + (controller: UIDocumentInteractionController; canPerformAction: SEL) + : Boolean; cdecl; [MethodName('documentInteractionController:performAction:')] - function documentInteractionControllerPerformAction(controller: UIDocumentInteractionController; performAction: SEL) + function documentInteractionControllerPerformAction + (controller: UIDocumentInteractionController; performAction: SEL) : Boolean; cdecl; end; - TiOSExternalFileViewer = class (TExternalFileViewer) + TiOSExternalFileViewer = class(TExternalFileViewer) private FController: UIDocumentInteractionController; FDelegate: TUIDocumentInteractionControllerDelegate; public - constructor Create(AOwner: TComponent; AForm: TForm); override; + constructor Create(AOwner: TComponent); override; procedure OpenFile(Path: string); override; procedure OpenURL(URL: string); override; @@ -84,27 +98,29 @@ TiOSExternalFileViewer = class (TExternalFileViewer) implementation {$IFDEF IOS} - { TiOSExternalFileViewer } -constructor TiOSExternalFileViewer.Create(AOwner: TComponent; AForm: TForm); +constructor TiOSExternalFileViewer.Create(AOwner: TComponent); begin inherited; end; procedure TiOSExternalFileViewer.OpenFile(Path: string); var - Url: NSUrl; + URL: NSUrl; begin - Url := TNSUrl.Wrap(TNSURL.OCClass.fileURLWithPath(StrToNSStr(Path))); + try + URL := TNSUrl.Wrap(TNSUrl.OCClass.fileURLWithPath(StrToNSStr(Path))); - self.FController := TUIDocumentInteractionController.Wrap( - TUIDocumentInteractionController.OCClass.interactionControllerWithURL(Url) - ); - FDelegate := TUIDocumentInteractionControllerDelegate.Create(self); - self.FController.setDelegate(self.FDelegate.GetObjectID); + self.FController := TUIDocumentInteractionController.Wrap + (TUIDocumentInteractionController.OCClass. + interactionControllerWithURL(URL)); + FDelegate := TUIDocumentInteractionControllerDelegate.Create(self); + self.FController.setDelegate(self.FDelegate.GetObjectID); - self.FController.presentPreviewAnimated(true); + self.FController.presentPreviewAnimated(true); + except + end; end; procedure TiOSExternalFileViewer.OpenURL(URL: string); @@ -114,64 +130,73 @@ procedure TiOSExternalFileViewer.OpenURL(URL: string); { TUIDocumentInteractionControllerDelegate } -constructor TUIDocumentInteractionControllerDelegate.Create( - AViewer: TiOSExternalFileViewer); +constructor TUIDocumentInteractionControllerDelegate.Create + (AViewer: TiOSExternalFileViewer); begin inherited Create; self.FViewer := AViewer; end; -function TUIDocumentInteractionControllerDelegate.documentInteractionControllerCanPerformAction( - controller: UIDocumentInteractionController; canPerformAction: SEL): Boolean; +function TUIDocumentInteractionControllerDelegate. + documentInteractionControllerCanPerformAction + (controller: UIDocumentInteractionController; canPerformAction: SEL): Boolean; begin Result := true; end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerDidDismissOpenInMenu( - controller: UIDocumentInteractionController); +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerDidDismissOpenInMenu + (controller: UIDocumentInteractionController); begin end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerDidDismissOptionsMenu( - controller: UIDocumentInteractionController); +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerDidDismissOptionsMenu + (controller: UIDocumentInteractionController); begin end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerDidEndPreview( - controller: UIDocumentInteractionController); +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerDidEndPreview(controller + : UIDocumentInteractionController); begin end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerDidEndSendingToApplication( - controller: UIDocumentInteractionController; +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerDidEndSendingToApplication + (controller: UIDocumentInteractionController; didEndSendingToApplication: NSString); begin end; -function TUIDocumentInteractionControllerDelegate.documentInteractionControllerPerformAction( - controller: UIDocumentInteractionController; performAction: SEL): Boolean; +function TUIDocumentInteractionControllerDelegate. + documentInteractionControllerPerformAction(controller + : UIDocumentInteractionController; performAction: SEL): Boolean; begin Result := true; end; -function TUIDocumentInteractionControllerDelegate.documentInteractionControllerRectForPreview( - controller: UIDocumentInteractionController): CGRect; +function TUIDocumentInteractionControllerDelegate. + documentInteractionControllerRectForPreview + (controller: UIDocumentInteractionController): CGRect; begin end; -function TUIDocumentInteractionControllerDelegate.documentInteractionControllerViewControllerForPreview( - controller: UIDocumentInteractionController): UIViewController; +function TUIDocumentInteractionControllerDelegate. + documentInteractionControllerViewControllerForPreview + (controller: UIDocumentInteractionController): UIViewController; var h: TiOSWindowHandle; w: UIWindow; v: UIViewController; begin + h := WindowHandleToPlatform(self.FViewer.FForm.Handle); w := h.Wnd; v := w.rootViewController; @@ -179,33 +204,38 @@ function TUIDocumentInteractionControllerDelegate.documentInteractionControllerV Result := v; end; -function TUIDocumentInteractionControllerDelegate.documentInteractionControllerViewForPreview( - controller: UIDocumentInteractionController): UIView; +function TUIDocumentInteractionControllerDelegate. + documentInteractionControllerViewForPreview + (controller: UIDocumentInteractionController): UIView; begin end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerWillBeginPreview( - controller: UIDocumentInteractionController); +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerWillBeginPreview + (controller: UIDocumentInteractionController); begin end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerWillBeginSendingToApplication( - controller: UIDocumentInteractionController; +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerWillBeginSendingToApplication + (controller: UIDocumentInteractionController; willBeginSendingToApplication: NSString); begin end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerWillPresentOpenInMenu( - controller: UIDocumentInteractionController); +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerWillPresentOpenInMenu + (controller: UIDocumentInteractionController); begin end; -procedure TUIDocumentInteractionControllerDelegate.documentInteractionControllerWillPresentOptionsMenu( - controller: UIDocumentInteractionController); +procedure TUIDocumentInteractionControllerDelegate. + documentInteractionControllerWillPresentOptionsMenu + (controller: UIDocumentInteractionController); begin end; From cca83903acf9ee804c24e1738132b649d5caacfa Mon Sep 17 00:00:00 2001 From: aBit Systems Date: Sun, 26 May 2019 22:02:21 +0800 Subject: [PATCH 2/2] Changes to support Android Secure File --- .../Android/UExternalFileViewer.Android.pas | 255 +++++++++--------- 1 file changed, 122 insertions(+), 133 deletions(-) diff --git a/Source/Android/UExternalFileViewer.Android.pas b/Source/Android/UExternalFileViewer.Android.pas index 61bf2fc..24d29df 100644 --- a/Source/Android/UExternalFileViewer.Android.pas +++ b/Source/Android/UExternalFileViewer.Android.pas @@ -1,133 +1,122 @@ -{****************************************************} -{ } -{ firemonkey-external-file-viewer } -{ } -{ Copyright (C) 2018 Code Partners Pty Ltd } -{ } -{ http://www.code-partners.com } -{ } -{****************************************************} -{ } -{ This Source Code Form is subject to the terms of } -{ the Mozilla Public License, v. 2.0. If a copy of } -{ the MPL was not distributed with this file, You } -{ can obtain one at } -{ } -{ http://mozilla.org/MPL/2.0/ } -{ } -{****************************************************} -unit UExternalFileViewer.Android; - -interface - -{$IFDEF ANDROID} - -uses - System.SysUtils, System.Classes, FMX.Forms, UExternalFileViewer, System.IOUtils, - Androidapi.JNI.GraphicsContentViewText, - Androidapi.JNIBridge, - Androidapi.JNI.JavaTypes, - Androidapi.JNI.Net, - Androidapi.JNI.Os, - Androidapi.JNI.Util, - Androidapi.Helpers, - Androidapi.JNI.Environment, - Androidapi.JNI.Webkit, - FMX.Helpers.Android; - -type - TAndroidExternalFileViewer = class (TExternalFileViewer) - private - function GetMimeType(Uri: Jnet_Uri): JString; - public - procedure OpenFile(Path: string); override; - procedure OpenURL(URL: string); override; - end; - -{$ENDIF} - -implementation - -{$IFDEF ANDROID} - -uses - FMX.Dialogs; - -{ TAndroidExternalFileViewer } - -procedure TAndroidExternalFileViewer.OpenFile(Path: string); -var - &OriginalFile, PublicDirectoryFile, PublicFile: JFile; - PublicDirectoryPath, PublicPath: string; - - Uri: Jnet_Uri; - Intent: JIntent; -begin - inherited; - - if Path.StartsWith(System.IOUtils.TPath.GetDocumentsPath()) then begin - &OriginalFile := TJFile.JavaClass.init(StringToJString(Path)); - - PublicDirectoryPath := (JStringToString(TJEnvironment.JavaClass.getExternalStorageDirectory.getAbsolutePath) + '/Documents'); - PublicPath := PublicDirectoryPath + PathDelim + ExtractFileName(Path); PublicDirectoryFile := TJFile.JavaClass.init(StringToJString(PublicDirectoryPath)); if (not PublicDirectoryFile.exists) then begin PublicDirectoryFile.mkdir; end; if (not FileExists(PublicPath)) then TFile.Copy(JStringToString(&OriginalFile.getAbsolutePath), PublicPath); - PublicFile := TJFile.JavaClass.init(StringToJString(PublicPath)); - end - else begin - PublicFile := TJFile.JavaClass.init(StringToJString(Path)); - end; - - Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW); - Uri := TJnet_Uri.JavaClass.fromFile(PublicFile); -// Intent.setDataAndType(Uri, StringToJString('application/pdf')); - Intent.setDataAndType(Uri, self.GetMimeType(Uri)); - Intent.setFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NO_HISTORY); - - TAndroidHelper.Activity.startActivity(Intent); -end; - -procedure TAndroidExternalFileViewer.OpenURL(URL: string); -var - Intent: JIntent; - Uri: Jnet_Uri; -begin - inherited; - - Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW); - -// Intent.setDataAndType(TJnet_Uri.JavaClass.parse(StringToJString(URL)), StringToJString('application/pdf')); - - Uri := TJnet_Uri.JavaClass.parse(StringToJString(URL)); - Intent.setDataAndType(Uri, self.GetMimeType(Uri)); - - Intent.setFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NO_HISTORY); - - TAndroidHelper.Activity.startActivity(Intent); -end; - -function TAndroidExternalFileViewer.GetMimeType(Uri: Jnet_Uri): JString; -var - MimeType: JString; - ContentResolver: JContentResolver; - FileExtension: JString; -begin - // https://stackoverflow.com/a/31691791/2899073 - - MimeType := nil; - if (Uri.getScheme.equals(TJContentResolver.JavaClass.SCHEME_CONTENT)) then begin - ContentResolver := TAndroidHelper.Context.getContentResolver(); - MimeType := ContentResolver.getType(uri); - end - else begin - FileExtension := TJMimeTypeMap.JavaClass.getFileExtensionFromUrl(uri.toString()); - - MimeType := TJMimeTypeMap.JavaClass.getSingleton().getMimeTypeFromExtension( - fileExtension.toLowerCase() - ); - end; - - Result := MimeType; -end; - -{$ENDIF} - -end. +{****************************************************} +{ } +{ firemonkey-external-file-viewer } +{ } +{ Copyright (C) 2018 Code Partners Pty Ltd } +{ } +{ http://www.code-partners.com } +{ } +{****************************************************} +{ } +{ This Source Code Form is subject to the terms of } +{ the Mozilla Public License, v. 2.0. If a copy of } +{ the MPL was not distributed with this file, You } +{ can obtain one at } +{ } +{ http://mozilla.org/MPL/2.0/ } +{ } +{****************************************************} +unit UExternalFileViewer.Android; + +interface + +{$IFDEF ANDROID} + +uses + System.SysUtils, System.Classes, FMX.Forms, FMX.ExternalFileViewer, + System.IOUtils, + Androidapi.JNI.GraphicsContentViewText, + Androidapi.JNIBridge, + Androidapi.JNI.JavaTypes, + Androidapi.JNI.Net, + Androidapi.JNI.Os, + Androidapi.JNI.Util, + Androidapi.Helpers, + Androidapi.JNI.Environment, + Androidapi.JNI.Webkit, + FMX.Helpers.Android; + +type + TAndroidExternalFileViewer = class(TExternalFileViewer) + private + function GetMimeType(Uri: Jnet_Uri): JString; + public + procedure OpenFile(Path: string); override; + procedure OpenURL(URL: string); override; + end; + +{$ENDIF} + +implementation + +{$IFDEF ANDROID} + +uses + FMX.Dialogs; + +{ TAndroidExternalFileViewer } + +procedure TAndroidExternalFileViewer.OpenFile(Path: string); +var + Uri: Jnet_Uri; + Intent: JIntent; +begin + inherited; + + Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW); + + Uri := TAndroidHelper.JFileToJURI + (TJFile.JavaClass.init(StringToJString(Path))); + + Intent.setDataAndType(Uri, self.GetMimeType(Uri)); + Intent.setFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION); + + TAndroidHelper.Activity.startActivity(Intent); +end; + +procedure TAndroidExternalFileViewer.OpenURL(URL: string); +var + Intent: JIntent; + Uri: Jnet_Uri; +begin + inherited; + + Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_VIEW); + + Uri := TJnet_Uri.JavaClass.parse(StringToJString(URL)); + Intent.setDataAndType(Uri, self.GetMimeType(Uri)); + + Intent.setFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NO_HISTORY); + + TAndroidHelper.Activity.startActivity(Intent); +end; + +function TAndroidExternalFileViewer.GetMimeType(Uri: Jnet_Uri): JString; +var + MimeType: JString; + ContentResolver: JContentResolver; + FileExtension: JString; +begin + // https://stackoverflow.com/a/31691791/2899073 + + MimeType := nil; + if (Uri.getScheme.equals(TJContentResolver.JavaClass.SCHEME_CONTENT)) then + begin + ContentResolver := TAndroidHelper.Context.getContentResolver(); + MimeType := ContentResolver.getType(Uri); + end + else + begin + FileExtension := TJMimeTypeMap.JavaClass.getFileExtensionFromUrl + (Uri.toString()); + + MimeType := TJMimeTypeMap.JavaClass.getSingleton().getMimeTypeFromExtension + (FileExtension.toLowerCase()); + end; + + Result := MimeType; +end; + +{$ENDIF} + +end.