|
@@ -1,3600 +0,0 @@
|
|
|
-unit FlyFilesUtils;
|
|
|
-
|
|
|
-(* ************************************************ *)
|
|
|
-(* *)
|
|
|
-(* 设计:爱吃猪头肉 & Flying Wang 2013-11-30 *)
|
|
|
-(* 上面的版权声明请不要移除。 *)
|
|
|
-(* Ver 1.0.2014.808 *)
|
|
|
-(* *)
|
|
|
-(* ************************************************ *)
|
|
|
-
|
|
|
-//1.0.2014.1108
|
|
|
-//支持 UTF8 的检查。
|
|
|
-
|
|
|
-//1.0.2014.908
|
|
|
-//支持 XE7。
|
|
|
-
|
|
|
-//1.0.2014.808
|
|
|
-//增加函数 IsPadOrPC。
|
|
|
-
|
|
|
-//1.0.2014.805
|
|
|
-//增加安卓下的获取 内存 SD 卡空间的函数。
|
|
|
-
|
|
|
-//1.0.2014.419
|
|
|
-//增加对 XE6 的支持。
|
|
|
-
|
|
|
-//1.0.2014.225
|
|
|
-//增加对 JNI 的接口查找功能。不完善。
|
|
|
-
|
|
|
-//1.0.2013.1219
|
|
|
-//在 亚瑟(Arthur) 3140223 的启发下,增加了更多的 SD 目录。
|
|
|
-
|
|
|
-//1.0.2013.1217
|
|
|
-//增加一个 FindSDCardSubPath 函数,用于查找指定的目录。
|
|
|
-
|
|
|
-//1.0.2013.1206
|
|
|
-//增加 [佛山]N.E(1024317) 9:36:38 提供的几个 SD 卡的路径。
|
|
|
-
|
|
|
-interface
|
|
|
-
|
|
|
-uses System.SysUtils,
|
|
|
- System.Classes,
|
|
|
-{$IFDEF ANDROID}
|
|
|
- Androidapi.JNIBridge,
|
|
|
- Androidapi.IOUtils,
|
|
|
-{$ENDIF ANDROID}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
- Winapi.Windows,
|
|
|
-{$ENDIF MSWINDOWS}
|
|
|
-{$IFDEF POSIX}
|
|
|
- Posix.Dlfcn, Posix.Fcntl, Posix.SysStat, Posix.SysTime, Posix.SysTypes, Posix.Locale,
|
|
|
-{$ENDIF POSIX}
|
|
|
-{$IFDEF PC_MAPPED_EXCEPTIONS}
|
|
|
- System.Internal.Unwinder,
|
|
|
-{$ENDIF PC_MAPPED_EXCEPTIONS}
|
|
|
-{$IFDEF MACOS}
|
|
|
- Macapi.Mach, Macapi.CoreServices, Macapi.CoreFoundation,
|
|
|
-{$ENDIF MACOS}
|
|
|
- System.SysConst,
|
|
|
- System.IOUtils;
|
|
|
-
|
|
|
-var
|
|
|
- Error_NotFoundFileManager_Str: string = 'Not Found FileManager.';
|
|
|
-
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 返回大小写敏感的文件或路径名称
|
|
|
-/// </summary>
|
|
|
-/// <param name="FileName">
|
|
|
-/// 文件或路径名
|
|
|
-/// </param>
|
|
|
-/// <param name="RootPath">
|
|
|
-/// <para>
|
|
|
-/// 检查路径的根目录
|
|
|
-/// </para>
|
|
|
-/// <para>
|
|
|
-/// 当大小写检查到此目录时停止,不再继续检查。
|
|
|
-/// </para>
|
|
|
-/// </param>
|
|
|
-function GetCaseSensitiveFileName(const FileName: string; RootPath: string = ''): string;
|
|
|
-
|
|
|
-
|
|
|
-const
|
|
|
- /// <summary>
|
|
|
- /// 外置设备的数量
|
|
|
- /// </summary>
|
|
|
- OTGDeivceCount = 16;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// USB 磁盘,例如 U 盘、移动硬盘等
|
|
|
- /// </summary>
|
|
|
- UsbDiskStartIndex = 255;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// 外置光驱
|
|
|
- /// </summary>
|
|
|
- CDROMStartIndex = 255 + OTGDeivceCount;
|
|
|
-
|
|
|
-const
|
|
|
- /// <summary>
|
|
|
- /// 默认的删除等待时间,单位微秒
|
|
|
- /// </summary>
|
|
|
- DeleteDirectories_WaitMinSecond = 2000;
|
|
|
-
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 检查 SD 卡或路径是否可用
|
|
|
-/// </summary>
|
|
|
-function isPathCanUseNow(const PathOrDir: string; const Default: Boolean = True): Boolean;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 检查 SD 卡或路径是否写入
|
|
|
-/// </summary>
|
|
|
-function TestPathCanWrite(const PathOrDir: string): Boolean;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 获取 手机存储 或 SD 卡的路径
|
|
|
-/// </summary>
|
|
|
-/// <param name="Index">
|
|
|
-/// 0 为 手机存储 1 为 SD 卡
|
|
|
-/// </param>
|
|
|
-/// <returns>
|
|
|
-/// <para>
|
|
|
-/// 如果找到,返回路径。带 / 或 \
|
|
|
-/// </para>
|
|
|
-/// <para>
|
|
|
-/// 没找到,返回一个错误的路径。
|
|
|
-/// </para>
|
|
|
-/// </returns>
|
|
|
-function GetSDCardPath(Index: Integer = 0): string;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 查找 手机存储 或 SD 卡上的某个路径
|
|
|
-/// </summary>
|
|
|
-/// <param name="SubPath">
|
|
|
-/// 被查找的子路径
|
|
|
-/// </param>
|
|
|
-/// <param name="Index">
|
|
|
-/// 0 为 手机存储 1 为 SD 卡
|
|
|
-/// </param>
|
|
|
-/// <returns>
|
|
|
-/// 如果找到,返回路径。带 / 或 \ 没找到,返回一个错误的路径。
|
|
|
-/// </returns>
|
|
|
-function FindSDCardSubPath(SubPath: string; Index: Integer = 0): string;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 获取当成工程的运行路径
|
|
|
-/// </summary>
|
|
|
-function GetAppPath: string;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 查找一个路径下的指定格式的文件
|
|
|
-/// </summary>
|
|
|
-/// <param name="Path">
|
|
|
-/// 路径,必须用通配符结束。例如 /*
|
|
|
-/// </param>
|
|
|
-/// <param name="Attr">
|
|
|
-/// 需要查找的文件的属性
|
|
|
-/// </param>
|
|
|
-/// <param name="List">
|
|
|
-/// 返回一个文件名或目录名的列表
|
|
|
-/// </param>
|
|
|
-/// <param name="JustFile">
|
|
|
-/// 是否只查找文件
|
|
|
-/// </param>
|
|
|
-/// <returns>
|
|
|
-/// 无意义
|
|
|
-/// </returns>
|
|
|
-function BuildFileListInAPath(const Path: string; const Attr: Integer; const List: TStrings;
|
|
|
- JustFile: Boolean = False): Boolean; overload;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 查找一个路径下的指定格式的文件
|
|
|
-/// </summary>
|
|
|
-/// <param name="Path">
|
|
|
-/// 路径,必须用通配符结束。例如 /*
|
|
|
-/// </param>
|
|
|
-/// <param name="Attr">
|
|
|
-/// 需要查找的文件的属性
|
|
|
-/// </param>
|
|
|
-/// <param name="JustFile">
|
|
|
-/// 是否只查找文件
|
|
|
-/// </param>
|
|
|
-/// <returns>
|
|
|
-/// 返回换行分割的文件名或目录的列表
|
|
|
-/// </returns>
|
|
|
-function BuildFileListInAPath(const Path: string; const Attr: Integer;
|
|
|
- JustFile: Boolean = False): string; overload;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 查找指定路径下的文件
|
|
|
-/// </summary>
|
|
|
-/// <param name="DirName">
|
|
|
-/// 路径
|
|
|
-/// </param>
|
|
|
-/// <param name="SearchFilter">
|
|
|
-/// 通配符组成的查找格式
|
|
|
-/// </param>
|
|
|
-/// <param name="FileAttribs">
|
|
|
-/// 需要查找的文件的属性
|
|
|
-/// </param>
|
|
|
-/// <param name="isIncludeSubDirName">
|
|
|
-/// 是否包含子目录的名字
|
|
|
-/// </param>
|
|
|
-/// <param name="Recursion">
|
|
|
-/// 是否递归找子目录
|
|
|
-/// </param>
|
|
|
-/// <param name="FullName">
|
|
|
-/// 是否返回完整路径
|
|
|
-/// </param>
|
|
|
-/// <returns>
|
|
|
-/// 返回换行分割的文件名或目录的列表
|
|
|
-/// </returns>
|
|
|
-function GetFileNamesFromDirectory(const DirName: string; const SearchFilter: string = '*';
|
|
|
- const FileAttribs: Integer = faAnyFile; const isIncludeSubDirName: Boolean = False; const Recursion: Boolean = False;
|
|
|
- const FullName: Boolean = False): string;
|
|
|
-
|
|
|
-//可以用 TDirectory.Delete 代替下面的功能。
|
|
|
-/// <summary>
|
|
|
-/// 删除目录下指定的文件
|
|
|
-/// </summary>
|
|
|
-/// <param name="Source">
|
|
|
-/// 被删除的文件路径,可以使用通配符
|
|
|
-/// </param>
|
|
|
-/// <param name="AbortOnFailure">
|
|
|
-/// 失败时是否退出
|
|
|
-/// </param>
|
|
|
-/// <param name="YesToAll">
|
|
|
-/// 删掉所有文件,包括只读的。仅 WIN32 下有效。
|
|
|
-/// </param>
|
|
|
-/// <param name="WaitMinSecond">
|
|
|
-/// 检查文件删除的等待时间,单位 微秒
|
|
|
-/// </param>
|
|
|
-/// <returns>
|
|
|
-/// 是否删除完成
|
|
|
-/// </returns>
|
|
|
-function DeleteDirectoryByEcho(const Source: string;
|
|
|
- AbortOnFailure: Boolean = False; YesToAll: Boolean = True;
|
|
|
- WaitMinSecond: Integer = DeleteDirectories_WaitMinSecond): Boolean;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
-/// 获取指定路径的总存储大小
|
|
|
-/// </summary>
|
|
|
-function GetTotalSpaceSize(Path: string = PathDelim): UInt64;
|
|
|
-/// <summary>
|
|
|
-/// 获取指定路径的可以使用的存储大小
|
|
|
-/// </summary>
|
|
|
-function GetAvailableSpaceSize(Path: string = PathDelim): UInt64;
|
|
|
-/// <summary>
|
|
|
-/// 获取指定路径的剩余(包括不可使用的)存储大小
|
|
|
-/// </summary>
|
|
|
-function GetFreeSpaceSize(Path: string = PathDelim): UInt64;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 获取总内存大小
|
|
|
-{$IFDEF ANDROID}
|
|
|
-/// 感谢[上海]故国(370620516)
|
|
|
-{$ENDIF}
|
|
|
-/// </summary>
|
|
|
-function GetTotalMemorySize: UInt64;
|
|
|
-/// <summary>
|
|
|
-/// 获取剩余内存大小
|
|
|
-{$IFDEF ANDROID}
|
|
|
-/// 感谢[上海]故国(370620516)
|
|
|
-{$ENDIF}
|
|
|
-/// </summary>
|
|
|
-function GetFreeMemorySize: UInt64;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 安卓 IOS 返回是否是 PAD(平板)
|
|
|
-/// 其他平台,返回 True
|
|
|
-/// 很多手机的 DPI 是错的,所以获取的尺寸也就不正常了,
|
|
|
-/// 所以个别手机会被识别成 PAD。
|
|
|
-/// </summary>
|
|
|
-function IsPadOrPC: Boolean;
|
|
|
-//function IsPadOrPC(MiniScreenInches: Single = 6.2): Boolean;
|
|
|
-//function IsPad: Boolean;
|
|
|
-
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 在其他 APP 中打开文件。
|
|
|
-/// </summary>
|
|
|
-function OpenFileOnExtApp(const FileName: string; Https: Boolean = True): Boolean;
|
|
|
-
|
|
|
-function NowGMT_UTC: TDateTime;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 获取完整 URL 的 Encode 结果。
|
|
|
-/// Just UTF8
|
|
|
-/// </summary>
|
|
|
-function EncodeURLWithSchemeOrProtocol(const URL: string): string;
|
|
|
-
|
|
|
-//上面是跨平台函数。
|
|
|
-//下面是平台函数。
|
|
|
-
|
|
|
-{$IFDEF ANDROID}
|
|
|
-
|
|
|
-function GetVolumePaths: string;
|
|
|
-
|
|
|
-function GetExternalStoragePath: string;
|
|
|
-
|
|
|
-//var
|
|
|
-// ExterStoragePathCanRead: Boolean = True;
|
|
|
-// ExterStoragePathCanWrite: Boolean = True;
|
|
|
-// SDMountedMessageReceived: Boolean = False;
|
|
|
-function GetExterStoragePath: string;
|
|
|
-function GetInnerStoragePath: string;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// It check SDCard0 Removable
|
|
|
-/// </summary>
|
|
|
-function GetIsExternalStorageRemovable: Boolean;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 很多手机的 DPI 是错的,所以获取的尺寸也就不正常了。
|
|
|
-/// </summary>
|
|
|
-function GetScreenClientInches: Single;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 获取安卓下剩余内存大小
|
|
|
-/// </summary>
|
|
|
-//function GetActiveMemorySize: UInt64;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 查找一个 JAVA 类是否可以使用
|
|
|
-/// </summary>
|
|
|
-/// <param name="NamePath">
|
|
|
-/// 类的全路径
|
|
|
-/// </param>
|
|
|
-function IsCanFindJavaClass(const NamePath: string): Boolean;
|
|
|
-function IsCanFindJavaMethod(const MethodName, Signature: string; const CalssNamePath: string = ''): Boolean;
|
|
|
-function IsCanFindJavaStaticMethod(const MethodName, Signature: string; const CalssNamePath: string = ''): Boolean;
|
|
|
-
|
|
|
-type
|
|
|
- TGetFileNameListener = reference to procedure(const IsOK: Boolean; const FileName:string);
|
|
|
- TGetFileNameLIsternerMethod = procedure (const IsOK: Boolean; const FileName:string) of object;
|
|
|
-
|
|
|
-function OpenFileDialog(Title, FileExtension:string; GetFileNameCallBack: TGetFileNameListener): Boolean; overload;
|
|
|
-function OpenFileDialog(Title, FileExtension:string; GetFileNameCallBack: TGetFileNameLIsternerMethod): Boolean; overload;
|
|
|
-
|
|
|
-function CheckPermission(const APermissionName: string): Boolean;
|
|
|
-
|
|
|
-const
|
|
|
- C_android_permission_EXTERNAL_STORAGE = 'android.permission.WRITE_EXTERNAL_STORAGE';
|
|
|
-// C_android_permission_WRITE_MEDIA = 'android.permission.WRITE_MEDIA_STORAGE';
|
|
|
-function CanWriteExterStorage: Boolean;
|
|
|
-
|
|
|
-/// <summary>
|
|
|
-/// 更新相册
|
|
|
-/// </summary>
|
|
|
-procedure UpdateAlbum(FileNames: string);
|
|
|
-
|
|
|
-function ReadNoSizeFileToString(const AFileName: string): string;
|
|
|
-function ReadFileToString(const AFileName: string): string;
|
|
|
-
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-implementation
|
|
|
-
|
|
|
-uses
|
|
|
-{$IFDEF ANDROID}
|
|
|
-{$IF CompilerVersion >= 27.0} // >= XE6
|
|
|
- Androidapi.Helpers,
|
|
|
-// FMX.Helpers.Android,
|
|
|
-{$ENDIF}
|
|
|
-{$IF CompilerVersion < 28.0} // < XE7
|
|
|
- FMX.Helpers.Android,
|
|
|
-{$ENDIF}
|
|
|
- Androidapi.Jni,
|
|
|
- Androidapi.JNI.Environment,
|
|
|
- Androidapi.JNI.StatFs,
|
|
|
- Androidapi.JNI.Stream2,
|
|
|
- Androidapi.JNI.ActivityManager,
|
|
|
- Androidapi.JNI.JavaTypes,
|
|
|
- Androidapi.NativeActivity,
|
|
|
- Androidapi.JNI.GraphicsContentViewText,
|
|
|
- Androidapi.JNI.Util,
|
|
|
- Androidapi.JNI.android.os.storage.StorageManager,
|
|
|
- Androidapi.JNI.java.lang.FlyUtils,
|
|
|
- Androidapi.JNI.Webkit,
|
|
|
-// Androidapi.JNI.Embarcadero,
|
|
|
- Androidapi.JNI.App,
|
|
|
- Androidapi.JNI.Net,
|
|
|
- Androidapi.JNI.Media,
|
|
|
- Androidapi.JNI.Provider,
|
|
|
-{$ENDIF}
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
- iOSapi.Foundation,
|
|
|
- Macapi.ObjectiveC,
|
|
|
- FMX.Helpers.iOS,
|
|
|
-// iOSapi.UIDevice2,
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
- Winapi.ShellApi,
|
|
|
-{$ENDIF}
|
|
|
-// FMX.Dialogs,
|
|
|
-{$IF CompilerVersion >= 29.0} // XE8
|
|
|
- System.NetEncoding,
|
|
|
-{$ELSE}
|
|
|
- IdURI,
|
|
|
-{$ENDIF}
|
|
|
- System.Rtti,
|
|
|
- System.TypInfo,
|
|
|
- System.Messaging,
|
|
|
- System.Math;
|
|
|
-
|
|
|
-
|
|
|
-//来自 inc 内部的 类型。
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-type
|
|
|
-{ Used by other time functions. }
|
|
|
- tm = record
|
|
|
- tm_sec: Integer; // Seconds. [0-60] (1 leap second)
|
|
|
- tm_min: Integer; // Minutes. [0-59]
|
|
|
- tm_hour: Integer; // Hours.[0-23]
|
|
|
- tm_mday: Integer; // Day.[1-31]
|
|
|
- tm_mon: Integer; // Month.[0-11]
|
|
|
- tm_year: Integer; // Year since 1900
|
|
|
- tm_wday: Integer; // Day of week [0-6] (Sunday = 0)
|
|
|
- tm_yday: Integer; // Days of year [0-365]
|
|
|
- tm_isdst: Integer; // Daylight Savings flag [-1/0/1]
|
|
|
- tm_gmtoff: LongInt; // Seconds east of UTC
|
|
|
- tm_zone: MarshaledAString; // Timezone abbreviation
|
|
|
- end;
|
|
|
- {$EXTERNALSYM tm}
|
|
|
- Ptm = ^tm;
|
|
|
-{$ELSEIF DEFINED(ANDROID)}
|
|
|
-{ Used by other time functions. }
|
|
|
-type
|
|
|
- tm = record
|
|
|
- tm_sec: Integer; // Seconds. [0-60] (1 leap second)
|
|
|
- tm_min: Integer; // Minutes. [0-59]
|
|
|
- tm_hour: Integer; // Hours.[0-23]
|
|
|
- tm_mday: Integer; // Day.[1-31]
|
|
|
- tm_mon: Integer; // Month.[0-11]
|
|
|
- tm_year: Integer; // Year since 1900
|
|
|
- tm_wday: Integer; // Day of week [0-6] (Sunday = 0)
|
|
|
- tm_yday: Integer; // Days of year [0-365]
|
|
|
- tm_isdst: Integer; // Daylight Savings flag [-1/0/1]
|
|
|
- tm_gmtoff: LongInt; // Seconds east of UTC
|
|
|
- tm_zone: MarshaledAString; // Timezone abbreviation
|
|
|
- end;
|
|
|
- {$EXTERNALSYM tm}
|
|
|
- Ptm = ^tm;
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-
|
|
|
-//来自 inc 的函数定义。
|
|
|
-{$IFDEF POSIX}
|
|
|
-const
|
|
|
-{$IFDEF UNDERSCOREIMPORTNAME}
|
|
|
- _PU = '_';
|
|
|
-{$ELSE}
|
|
|
- _PU = '';
|
|
|
-{$ENDIF}
|
|
|
-const
|
|
|
- libc = '/usr/lib/libc.dylib';
|
|
|
- libpthread = '/usr/lib/libpthread.dylib';
|
|
|
- libiconv = '/usr/lib/libiconv.dylib';
|
|
|
- libdl = '/usr/lib/libdl.dylib';
|
|
|
-
|
|
|
-{$IF not Declared(_PU)}
|
|
|
-const
|
|
|
- // On Mac OSX, cdecl names have a preceeding underscore
|
|
|
- // if x86 native backend.
|
|
|
- {$IF Defined(UNDERSCOREIMPORTNAME)}
|
|
|
- _PU = '_';
|
|
|
- {$ELSE}
|
|
|
- _PU = '';
|
|
|
- {$ENDIF}
|
|
|
- {$EXTERNALSYM _PU}
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-const
|
|
|
-{$IFNDEF IOS}
|
|
|
- _INODE_SUFFIX = '$INODE64';
|
|
|
-{$ELSE IOS}
|
|
|
- _INODE_SUFFIX = '';
|
|
|
-{$ENDIF !IOS}
|
|
|
- {$EXTERNALSYM _INODE_SUFFIX}
|
|
|
-
|
|
|
-//具体函数定义开始。
|
|
|
-function _system(Name: MarshaledAString): Integer; cdecl;
|
|
|
- external libc name _PU + 'system';
|
|
|
-
|
|
|
-function tempnam(const Path: MarshaledAString; const Prefix: MarshaledAString): MarshaledAString; cdecl;
|
|
|
- external libc name _PU + 'tempnam';
|
|
|
-{$EXTERNALSYM tempnam}
|
|
|
-procedure free(p: Pointer); cdecl;
|
|
|
- external libc name _PU + 'free';
|
|
|
-{$EXTERNALSYM free}
|
|
|
-function gettimeofday(var timeval: timeval; timezone: Pointer): Integer; cdecl;
|
|
|
- external libc name _PU + 'gettimeofday';
|
|
|
-{$EXTERNALSYM gettimeofday}
|
|
|
-function gmtime_r(var Timer: time_t; var UnixTime: tm): Ptm; cdecl;
|
|
|
- external libc name _PU + 'gmtime_r';
|
|
|
-{$EXTERNALSYM gmtime_r}
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-//可以开始写函数了。
|
|
|
-
|
|
|
-function NowGMT_UTC: TDateTime;
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-var
|
|
|
- SystemTime: TSystemTime;
|
|
|
-begin
|
|
|
- GetSystemTime(SystemTime);
|
|
|
- Result := EncodeDate(SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay) +
|
|
|
- EncodeTime(SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds);
|
|
|
-end;
|
|
|
-{$ENDIF MSWINDOWS}
|
|
|
-{$IFDEF POSIX}
|
|
|
-var
|
|
|
- T: time_t;
|
|
|
- TV: timeval;
|
|
|
- UT: tm;
|
|
|
-begin
|
|
|
- gettimeofday(TV, nil);
|
|
|
- T := TV.tv_sec;
|
|
|
- gmtime_r(T, UT);
|
|
|
- Result := EncodeDate(UT.tm_year + 1900, UT.tm_mon + 1, UT.tm_mday) +
|
|
|
- EncodeTime(UT.tm_hour, UT.tm_min, UT.tm_sec, TV.tv_usec div 1000);
|
|
|
-end;
|
|
|
-{$ENDIF POSIX}
|
|
|
-
|
|
|
-function EncodeURLWithSchemeOrProtocol(const URL: string): string;
|
|
|
-var
|
|
|
- Protocol: string;
|
|
|
- AURL: string;
|
|
|
- AIndex: Integer;
|
|
|
-begin
|
|
|
-{$IF CompilerVersion >= 29.0} // XE8
|
|
|
- AURL := URL.Trim;
|
|
|
- Protocol := '';
|
|
|
- AIndex := AURL.IndexOf('//');
|
|
|
- if AIndex > 0 then
|
|
|
- begin
|
|
|
- Protocol := AURL.Substring(0, AIndex + 1); // has /
|
|
|
- AURL := AURL.Substring(AIndex + 1); // has /
|
|
|
- end;
|
|
|
- Result := Protocol + TNetEncoding.URL.EncodePath(AURL);
|
|
|
-{$ELSE}
|
|
|
- Result := TIdURI.URLEncode(Result);
|
|
|
-{$ENDIF}
|
|
|
-end;
|
|
|
-
|
|
|
-function EncodeURLWithOutSchemeOrProtocol(const URL: string; Https: Boolean = True): string;
|
|
|
-begin
|
|
|
- Result := URL;
|
|
|
- if FileExists(Result) then
|
|
|
- begin
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-{$ELSE}
|
|
|
- if Result.Substring(0, 1) <> '/' then
|
|
|
- begin
|
|
|
- Result := '/' + Result;
|
|
|
- end;
|
|
|
- Result := 'file://' + Result;
|
|
|
-{$ENDIF}
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- if Https then
|
|
|
- begin
|
|
|
- Result := 'https://' + URL;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := 'http://' + URL;
|
|
|
- end;
|
|
|
- Result := EncodeURLWithSchemeOrProtocol(Result);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function OpenFileOnExtApp(const FileName: string; Https: Boolean = True): Boolean;
|
|
|
-{$IFDEF ANDROID}
|
|
|
-var
|
|
|
- Intent: JIntent;
|
|
|
- FileExtension: string;
|
|
|
- mime: JMimeTypeMap;
|
|
|
- MIMEType: JString;
|
|
|
- TempStr,
|
|
|
- FileToOpen: string;
|
|
|
- AJFile: JFile;
|
|
|
- AJUri: Jnet_Uri;
|
|
|
-begin
|
|
|
-// There may be an issue with the geo: prefix and URLEncode.
|
|
|
-// will need to research
|
|
|
- Result := False;
|
|
|
- if FileName = '' then
|
|
|
- Exit;
|
|
|
- FileExtension := AnsiLowerCase(ExtractFileExt(FileName));
|
|
|
- if FileExtension = '' then
|
|
|
- Exit;
|
|
|
- mime := TJMimeTypeMap.JavaClass.getSingleton();
|
|
|
- MIMEType := nil;
|
|
|
- if mime <> nil then
|
|
|
- begin
|
|
|
- MIMEType := mime.getMimeTypeFromExtension(StringToJString(FileExtension.Substring(1)));
|
|
|
- end;
|
|
|
- if MIMEType <> nil then
|
|
|
- begin
|
|
|
- // 调用相应程序打开当前程序
|
|
|
- Intent := TJIntent.Create;
|
|
|
- Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
|
|
|
- //TempStr := IncludeTrailingPathDelimiter(TPath.GetDocumentsPath)
|
|
|
- TempStr := IncludeTrailingPathDelimiter(TPath.GetHomePath);
|
|
|
-{$IF CompilerVersion >= 33.0} // RAD10.3
|
|
|
- if FileExists(FileName) then
|
|
|
- begin
|
|
|
- FileToOpen := FileName;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- FileToOpen := EncodeURLWithOutSchemeOrProtocol(FileName, Https);
|
|
|
- end;
|
|
|
- if Pos(TempStr, FileToOpen) = 1 then
|
|
|
- begin
|
|
|
- AJFile := TJFile.JavaClass.init(StringToJString(FileToOpen));
|
|
|
- AJUri := TAndroidHelper.JFileToJURI(AJFile);
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
-{$ELSE}
|
|
|
- begin
|
|
|
-{$ENDIF}
|
|
|
- FileToOpen := EncodeURLWithOutSchemeOrProtocol(FileName, Https);
|
|
|
- AJUri := StrToJURI(FileToOpen);
|
|
|
- end;
|
|
|
- Intent.setDataAndType(AJUri, MIMEType);
|
|
|
- try
|
|
|
- SharedActivity.startActivity(Intent);
|
|
|
- Result := True;
|
|
|
- except
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
-end;
|
|
|
-{$ELSE}
|
|
|
-{$IFDEF IOS}
|
|
|
-var
|
|
|
- NSU: NSUrl;
|
|
|
- AURL: string;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- AURL := EncodeURLWithOutSchemeOrProtocol(FileName, Https);
|
|
|
- // iOS doesn't like spaces, so URL encode is important.
|
|
|
- NSU := StrToNSUrl(AURL);
|
|
|
- if TOSVersion.Check(9) or SharedApplication.canOpenURL(NSU) then
|
|
|
- try
|
|
|
- Result := SharedApplication.openUrl(NSU);
|
|
|
- except
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ELSE}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-var
|
|
|
- AURL: string;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- AURL := EncodeURLWithOutSchemeOrProtocol(FileName, Https);
|
|
|
- try
|
|
|
- ShellExecute(GetActiveWindow, 'open', PChar(AURL), '', '', SW_MAXIMIZE);
|
|
|
- Result := True;
|
|
|
- except
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ELSE}
|
|
|
-var
|
|
|
- M:TMarshaller;
|
|
|
- AURL: string;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- //AURL := 'open -a Safari ' + EncodeURLWithOutSchemeOrProtocol(AURL);
|
|
|
- AURL := 'open ' + EncodeURLWithOutSchemeOrProtocol(FileName, Https);
|
|
|
- try
|
|
|
- _system(M.AsAnsi(AURL, CP_UTF8).ToPointer);
|
|
|
- Result := True;
|
|
|
- except
|
|
|
- end;
|
|
|
-// raise Exception.Create('Not supported!');
|
|
|
-end;
|
|
|
-{$ENDIF MSWINDOWS}
|
|
|
-{$ENDIF IOS}
|
|
|
-{$ENDIF ANDROID}
|
|
|
-
|
|
|
-function IsPadOrPC: Boolean;
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-{$IFDEF IOS}
|
|
|
-begin
|
|
|
- Result := IsPad;
|
|
|
-end;
|
|
|
-{$ELSE IOS}
|
|
|
-begin
|
|
|
- Result := True;
|
|
|
-end;
|
|
|
-{$ENDIF IOS}
|
|
|
-{$ENDIF IOS or MACOS}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-begin
|
|
|
- Result := True;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF ANDROID}
|
|
|
-//var
|
|
|
-// ScreenInches2,
|
|
|
-// ScreenInches1,
|
|
|
-// x,y: Double;
|
|
|
-// dm: JDisplayMetrics;
|
|
|
-//begin
|
|
|
-// Result := False;
|
|
|
-// dm := GetJDisplayMetrics;
|
|
|
-// if dm = nil then exit;
|
|
|
-// x := dm.widthPixels;
|
|
|
-// y := dm.heightPixels;
|
|
|
-// try
|
|
|
-// ScreenInches1 := Sqrt((x * x / dm.xdpi / dm.xdpi) + (y * y / dm.ydpi / dm.ydpi));
|
|
|
-// ScreenInches2 := Sqr(x * x + y * Y ) / dm.densityDpi;
|
|
|
-// except
|
|
|
-// exit;
|
|
|
-// end;
|
|
|
-// Result := ScreenInches1 >= MiniScreenInches;
|
|
|
-// if Result then
|
|
|
-// Result := ScreenInches2 >= MiniScreenInches;
|
|
|
-//end;
|
|
|
-var
|
|
|
- IsTablet: Boolean;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- IsTablet := False;
|
|
|
-// CallInUIThreadAndWaitFinishing(
|
|
|
-// procedure
|
|
|
-// begin
|
|
|
- IsTablet := SharedActivity.getResources.getConfiguration.screenLayout and
|
|
|
- TJConfiguration.JavaClass.SCREENLAYOUT_SIZE_MASK >= TJConfiguration.JavaClass.SCREENLAYOUT_SIZE_LARGE;
|
|
|
-// end);
|
|
|
- Result := IsTablet;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-function IsPad: Boolean;
|
|
|
-begin
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-begin
|
|
|
- //code by [龟山]Aone(1467948783)
|
|
|
- Result := TOSVersion.Check(6, 1) and
|
|
|
- (GetSystemMetrics(SM_TABLETPC) <> 0) and
|
|
|
- ((GetSystemMetrics(SM_DIGITIZER) and NID_MULTI_INPUT) = NID_MULTI_INPUT);
|
|
|
-end;
|
|
|
-{$ELSE MSWINDOWS}
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-{$IFDEF IOS}
|
|
|
-begin
|
|
|
- Result := IsPad;
|
|
|
-end;
|
|
|
-{$ELSE IOS}
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
-end;
|
|
|
-{$ENDIF IOS}
|
|
|
-{$ELSE} //IF DEFINED(IOS) or DEFINED(MACOS)
|
|
|
- Result := IsPadOrPC;
|
|
|
-{$ENDIF IOS or MACOS}
|
|
|
-{$ENDIF MSWINDOWS}
|
|
|
-end;
|
|
|
-
|
|
|
-function GetTotalMemorySize: UInt64;
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-begin
|
|
|
-// Result := TUIDevice2.Wrap(TUIDevice2.OCClass.currentDevice).totalMemory;
|
|
|
- Result := NSRealMemoryAvailable;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-var
|
|
|
- lpBuffer : TMEMORYSTATUSEX;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- ZeroMemory(@lpBuffer, Sizeof(TMEMORYSTATUSEX));
|
|
|
- lpBuffer.dwLength := Sizeof(TMEMORYSTATUSEX);
|
|
|
- GlobalMemoryStatusEx(lpBuffer);
|
|
|
- Result := lpBuffer.ullTotalPhys;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF ANDROID}
|
|
|
-var
|
|
|
- Mgr: JActivityManager;
|
|
|
- MgrNative: JObject;
|
|
|
- MemInfo: JActivityManager_MemoryInfo;
|
|
|
- AStrings: TStringList;
|
|
|
- TempValue: string;
|
|
|
- AReader: JReader;
|
|
|
- ABufferedReader: JBufferedReader;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- MgrNative :=
|
|
|
-{$IF CompilerVersion >= 30.0} // >=RAD10
|
|
|
- TAndroidHelper.Context
|
|
|
-{$ELSE}
|
|
|
- SharedActivityContext
|
|
|
-{$ENDIF}
|
|
|
- .getSystemService(TJContext.JavaClass.ACTIVITY_SERVICE);
|
|
|
- if MgrNative <> nil then
|
|
|
- begin
|
|
|
- Mgr := TJActivityManager.Wrap((MgrNative as ILocalObject).GetObjectID);
|
|
|
- MemInfo := TJActivityManager_MemoryInfo.JavaClass.init;
|
|
|
- Mgr.getMemoryInfo(MemInfo);
|
|
|
- try
|
|
|
- Result := UInt64(MemInfo.totalMem);
|
|
|
- except
|
|
|
- //API level < 16
|
|
|
- try
|
|
|
- Result := UInt64(MemInfo.availMem);
|
|
|
- except
|
|
|
- Result := 0;
|
|
|
- end;
|
|
|
- if FileExists('/proc/meminfo') then
|
|
|
- begin
|
|
|
- AStrings := TStringList.Create;
|
|
|
- try
|
|
|
- AStrings.LineBreak := sLineBreak;
|
|
|
- AStrings.NameValueSeparator := ':';
|
|
|
- AStrings.Clear;
|
|
|
- AReader := TJFileReader.JavaClass.init(StringToJString('/proc/meminfo')) as JReader;
|
|
|
- ABufferedReader := TJBufferedReader.JavaClass.init(AReader);
|
|
|
- repeat
|
|
|
- TempValue := JStringToString(ABufferedReader.readLine);
|
|
|
- if TempValue <> '' then
|
|
|
- begin
|
|
|
- AStrings.Add(TempValue);
|
|
|
- end;
|
|
|
- until (not ABufferedReader.ready);
|
|
|
- ABufferedReader.close;
|
|
|
- TempValue := AStrings.Values['MemTotal'].Trim;
|
|
|
- AStrings.Clear;
|
|
|
- AStrings.NameValueSeparator := ' ';
|
|
|
- AStrings.Add(TempValue.Trim);
|
|
|
- TempValue := AStrings.Names[0];
|
|
|
-// ShowMessage(TempValue);
|
|
|
- Result := StrToInt64Def(TempValue, Result div 1024) * 1024;
|
|
|
- finally
|
|
|
- FreeAndNil(AStrings);
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-function GetFreeMemorySize: UInt64;
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-begin
|
|
|
- //Result := Max(0, GetTotalMemorySize -
|
|
|
- // TUIDevice2.Wrap(TUIDevice2.OCClass.currentDevice).userMemory);
|
|
|
- Result := NSRealMemoryAvailable;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-var
|
|
|
- lpBuffer : TMEMORYSTATUSEX;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- ZeroMemory(@lpBuffer, Sizeof(TMEMORYSTATUSEX));
|
|
|
- lpBuffer.dwLength := Sizeof(TMEMORYSTATUSEX);
|
|
|
- GlobalMemoryStatusEx(lpBuffer);
|
|
|
- Result := lpBuffer.ullAvailPhys;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF ANDROID}
|
|
|
-var
|
|
|
- Mgr: JActivityManager;
|
|
|
- MgrNative: JObject;
|
|
|
- MemInfo: JActivityManager_MemoryInfo;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- MgrNative :=
|
|
|
-{$IF CompilerVersion >= 30.0} // >=RAD10
|
|
|
- TAndroidHelper.Context
|
|
|
-{$ELSE}
|
|
|
- SharedActivityContext
|
|
|
-{$ENDIF}
|
|
|
- .getSystemService(TJContext.JavaClass.ACTIVITY_SERVICE);
|
|
|
- if MgrNative <> nil then
|
|
|
- begin
|
|
|
- Mgr := TJActivityManager.Wrap((MgrNative as ILocalObject).GetObjectID);
|
|
|
- MemInfo := TJActivityManager_MemoryInfo.JavaClass.init;
|
|
|
- Mgr.getMemoryInfo(MemInfo);
|
|
|
- try
|
|
|
- Result := UInt64(MemInfo.availMem);
|
|
|
- except
|
|
|
- Result := 0;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-function GetTotalSpaceSize(Path: string = PathDelim): UInt64;
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-var
|
|
|
- Dict: NSDictionary;
|
|
|
- P: Pointer;
|
|
|
-const
|
|
|
- FoundationFwk: string = '/System/Library/Frameworks/Foundation.framework/Foundation';
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- Dict := TNSFileManager.Wrap(TNSFileManager.OCClass.defaultManager).attributesOfFileSystemForPath(NSStr(Path), nil);
|
|
|
- if Dict = nil then
|
|
|
- Exit;
|
|
|
- P := Dict.objectForKey((CocoaNSStringConst(FoundationFwk, 'NSFileSystemSize') as ILocalObject).GetObjectID);
|
|
|
- if P <> nil then
|
|
|
- Result := TNSNumber.Wrap(P).unsignedLongLongValue;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-var
|
|
|
- lpFreeBytesAvailableToCaller,
|
|
|
- lpTotalNumberOfBytes,
|
|
|
- lpTotalNumberOfFreeBytes: Int64;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- lpTotalNumberOfBytes := MaxInt;
|
|
|
- if GetDiskFreeSpaceEx(pchar(ExtractFileDrive(Path)),
|
|
|
- lpFreeBytesAvailableToCaller,
|
|
|
- lpTotalNumberOfBytes, @lpTotalNumberOfFreeBytes) then
|
|
|
- begin
|
|
|
- Result := UInt64(lpTotalNumberOfBytes);
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF ANDROID}
|
|
|
-var
|
|
|
- AJFile: JFile;
|
|
|
- AJStatFs: JStatFs;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- AJFile := TJFile.JavaClass.init(StringToJString(Path));
|
|
|
- if AJFile = nil then exit;
|
|
|
- AJStatFs := TJStatFs.JavaClass.init(AJFile.getPath);
|
|
|
- if AJStatFs = nil then exit;
|
|
|
- Result := UInt64(AJStatFs.getBlockSize) * UInt64(AJStatFs.getBlockCount);
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-function GetFreeSpaceSize(Path: string = PathDelim): UInt64;
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-var
|
|
|
- Dict: NSDictionary;
|
|
|
- P: Pointer;
|
|
|
-const
|
|
|
- FoundationFwk: string = '/System/Library/Frameworks/Foundation.framework/Foundation';
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- Dict := TNSFileManager.Wrap(TNSFileManager.OCClass.defaultManager).attributesOfFileSystemForPath(NSStr(Path), nil);
|
|
|
- if Dict = nil then
|
|
|
- Exit;
|
|
|
- P := Dict.objectForKey((CocoaNSStringConst(FoundationFwk, 'NSFileSystemFreeSize') as ILocalObject).GetObjectID);
|
|
|
- if P <> nil then
|
|
|
- Result := TNSNumber.Wrap(P).unsignedLongLongValue;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-var
|
|
|
- lpFreeBytesAvailableToCaller,
|
|
|
- lpTotalNumberOfBytes,
|
|
|
- lpTotalNumberOfFreeBytes: Int64;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- lpTotalNumberOfFreeBytes := MaxInt;
|
|
|
- if GetDiskFreeSpaceEx(pchar(ExtractFileDrive(Path)),
|
|
|
- lpFreeBytesAvailableToCaller,
|
|
|
- lpTotalNumberOfBytes, @lpTotalNumberOfFreeBytes) then
|
|
|
- begin
|
|
|
- Result := UInt64(lpTotalNumberOfFreeBytes);
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF ANDROID}
|
|
|
-var
|
|
|
- AJFile: JFile;
|
|
|
- AJStatFs: JStatFs;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- AJFile := TJFile.JavaClass.init(StringToJString(Path));
|
|
|
- if AJFile = nil then exit;
|
|
|
- AJStatFs := TJStatFs.JavaClass.init(AJFile.getPath);
|
|
|
- if AJStatFs = nil then exit;
|
|
|
- Result := UInt64(AJStatFs.getBlockSize) * UInt64(AJStatFs.getFreeBlocks);
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-function GetAvailableSpaceSize(Path: string = PathDelim): UInt64;
|
|
|
-{$IF DEFINED(IOS) or DEFINED(MACOS)}
|
|
|
-begin
|
|
|
- Result := GetFreeSpaceSize(Path);
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-var
|
|
|
- lpFreeBytesAvailableToCaller,
|
|
|
- lpTotalNumberOfBytes,
|
|
|
- lpTotalNumberOfFreeBytes: Int64;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- lpFreeBytesAvailableToCaller := MaxInt;
|
|
|
- if GetDiskFreeSpaceEx(pchar(ExtractFileDrive(Path)),
|
|
|
- lpFreeBytesAvailableToCaller,
|
|
|
- lpTotalNumberOfBytes, @lpTotalNumberOfFreeBytes) then
|
|
|
- begin
|
|
|
- Result := UInt64(lpFreeBytesAvailableToCaller);
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-{$IFDEF ANDROID}
|
|
|
-var
|
|
|
- AJFile: JFile;
|
|
|
- AJStatFs: JStatFs;
|
|
|
-begin
|
|
|
- Result := 0;
|
|
|
- if DirectoryExists(Path) or FileExists(Path) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- raise Exception.Create('Path " ' + Path + '" not found.');
|
|
|
- end;
|
|
|
- AJFile := TJFile.JavaClass.init(StringToJString(Path));
|
|
|
- if AJFile = nil then exit;
|
|
|
- AJStatFs := TJStatFs.JavaClass.init(AJFile.getPath);
|
|
|
- if AJStatFs = nil then exit;
|
|
|
- Result := UInt64(AJStatFs.getBlockSize) * UInt64(AJStatFs.getAvailableBlocks);
|
|
|
-end;
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-{$IFDEF ANDROID}
|
|
|
-
|
|
|
-function CanWriteExterStorage: Boolean;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- Result := CheckPermission(C_android_permission_EXTERNAL_STORAGE);
|
|
|
-// if Result and TOSVersion.Check(4) then
|
|
|
-// begin
|
|
|
-// // 没有效果,而且返回 总是 False
|
|
|
-// Result := CheckPermission(C_android_permission_WRITE_MEDIA);
|
|
|
-// end;
|
|
|
-end;
|
|
|
-
|
|
|
-//copy form FMX.AddressBook.Android;
|
|
|
-function CheckPermission(const APermissionName: string): Boolean;
|
|
|
-var
|
|
|
- PackageName: JString;
|
|
|
-begin
|
|
|
- PackageName := TAndroidHelper.Context.getPackageName;
|
|
|
-// if TOSVersion.Check(6) then
|
|
|
-// begin
|
|
|
-// Result := TAndroidHelper.Context.checkSelfPermission(StringToJString(APermissionName)) =
|
|
|
-// TJPackageManager.JavaClass.PERMISSION_GRANTED;
|
|
|
-// exit;
|
|
|
-// end;
|
|
|
- Result := TAndroidHelper.Context.getPackageManager.checkPermission(StringToJString(APermissionName), PackageName) =
|
|
|
- TJPackageManager.JavaClass.PERMISSION_GRANTED;
|
|
|
-end;
|
|
|
-
|
|
|
-function isExternalStorageDocument(URI: Jnet_Uri): Boolean;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- if URI = nil then exit;
|
|
|
- Result := URI.getAuthority.equals(StringToJString('com.android.externalstorage.documents'));
|
|
|
-end;
|
|
|
-
|
|
|
-function isDownloadsDocument(URI: Jnet_Uri): Boolean;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- if URI = nil then exit;
|
|
|
- Result := URI.getAuthority.equals(StringToJString('com.android.providers.downloads.documents'));
|
|
|
-end;
|
|
|
-
|
|
|
-function isMediaDocument(URI: Jnet_Uri): Boolean;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- if URI = nil then exit;
|
|
|
- Result := URI.getAuthority.equals(StringToJString('com.android.providers.media.documents'));
|
|
|
-end;
|
|
|
-
|
|
|
-const
|
|
|
- FILE_SELECT_CODE = 0;
|
|
|
-
|
|
|
-var
|
|
|
- FMessageChooserID: Integer = 0;
|
|
|
- FGetFileNameCallBack1: TGetFileNameListener;
|
|
|
- FGetFileNameCallBack2: TGetFileNameLIsternerMethod;
|
|
|
-
|
|
|
-procedure HandleActivityMessageforChooser(const Sender: TObject; const M: TMessage);
|
|
|
-var
|
|
|
- MediaDocument,
|
|
|
- ExternalStorageDocument,
|
|
|
- IsOK: Boolean;
|
|
|
- DocType,
|
|
|
- DocIDs,
|
|
|
- FileScheme,
|
|
|
- FileName:string;
|
|
|
- URI: Jnet_Uri;
|
|
|
- cursor: JCursor;
|
|
|
- projection: TJavaObjectArray<JString>;
|
|
|
- column_index: Integer;
|
|
|
- DocIDInfos: TArray<string>;
|
|
|
- TempDocIDStr: JString;
|
|
|
- selection: JString;
|
|
|
- selectionArgs: TJavaObjectArray<JString>;
|
|
|
-begin
|
|
|
- IsOK := False;
|
|
|
- FileName := '';
|
|
|
- IsOK := M is TMessageResultNotification;
|
|
|
- if IsOK and (TMessageResultNotification(M).RequestCode = FILE_SELECT_CODE) then
|
|
|
- begin
|
|
|
- IsOK := (TMessageResultNotification(M).ResultCode = TJActivity.JavaClass.RESULT_OK);
|
|
|
- end;
|
|
|
- if IsOK then
|
|
|
- begin
|
|
|
- IsOK := TMessageResultNotification(M).Value <> nil;
|
|
|
- end;
|
|
|
- if IsOK then
|
|
|
- begin
|
|
|
- URI := TMessageResultNotification(M).Value.getData;
|
|
|
- IsOK := URI <> nil;
|
|
|
- end;
|
|
|
- FileName := '';
|
|
|
- if IsOK then
|
|
|
- begin
|
|
|
- FileScheme := JStringToString(URI.getScheme);
|
|
|
- if TOSVersion.Check(4, 4) and TJDocumentsContract.JavaClass.isDocumentUri(
|
|
|
-{$IF CompilerVersion >= 30.0} // >=RAD10
|
|
|
- TAndroidHelper.Context
|
|
|
-{$ELSE}
|
|
|
- SharedActivityContext
|
|
|
-{$ENDIF}
|
|
|
- , URI) then
|
|
|
- begin
|
|
|
- //http://blog.csdn.net/u011200844/article/details/43703593
|
|
|
- ExternalStorageDocument := False;
|
|
|
- MediaDocument := False;
|
|
|
- selection := nil;
|
|
|
- selectionArgs := nil;
|
|
|
- IsOK := False;
|
|
|
- if isDownloadsDocument(URI) then
|
|
|
- begin
|
|
|
- TempDocIDStr := TJDocumentsContract.JavaClass.getDocumentId(URI);
|
|
|
- URI := TJContentUris.JavaClass.withAppendedId(
|
|
|
- TJnet_Uri.JavaClass.parse(StringToJString('content://downloads/public_downloads')),
|
|
|
- TJLong.JavaClass.valueOf(TempDocIDStr).longValue);
|
|
|
- //后面会继续处理。
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- ExternalStorageDocument := isExternalStorageDocument(URI);
|
|
|
- if not ExternalStorageDocument then
|
|
|
- MediaDocument := isMediaDocument(URI);
|
|
|
- end;
|
|
|
- if ExternalStorageDocument or MediaDocument then
|
|
|
- begin
|
|
|
- DocIDs := JStringToString(TJDocumentsContract.JavaClass.getDocumentId(URI));
|
|
|
- DocIDInfos := DocIDs.Split([':']);
|
|
|
- if Length(DocIDInfos) > 1 then
|
|
|
- begin
|
|
|
- DocType := DocIDInfos[0];
|
|
|
- if ExternalStorageDocument then
|
|
|
- begin
|
|
|
- if SameText(DocType, 'primary') then
|
|
|
- begin
|
|
|
- FileName := GetSDCardPath(0) + DocIDInfos[1];
|
|
|
- IsOK := True;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- //后面会继续处理。
|
|
|
- end;
|
|
|
- end
|
|
|
- else if MediaDocument then
|
|
|
- begin
|
|
|
- if SameText(DocType, 'image') then
|
|
|
- begin
|
|
|
- URI := TJImages_Media.JavaClass.EXTERNAL_CONTENT_URI;
|
|
|
- IsOK := True;
|
|
|
- end
|
|
|
- else if SameText(DocType, 'video') then
|
|
|
- begin
|
|
|
- URI := TJVideo_Media.JavaClass.EXTERNAL_CONTENT_URI;
|
|
|
- IsOK := True;
|
|
|
- end
|
|
|
- else if SameText(DocType, 'audio') then
|
|
|
- begin
|
|
|
- URI := TJAudio_Media.JavaClass.EXTERNAL_CONTENT_URI;
|
|
|
- IsOK := True;
|
|
|
- end;
|
|
|
- if IsOK then
|
|
|
- begin
|
|
|
- selection := StringToJString('_id=?');
|
|
|
- selectionArgs := TJavaObjectArray<JString>.Create(1);
|
|
|
- selectionArgs.Items[0] := StringToJString(DocIDInfos[1]);
|
|
|
- IsOK := False;
|
|
|
- //后面会继续处理。
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end
|
|
|
- else
|
|
|
- IsOK := SameText('file', FileScheme);
|
|
|
- end
|
|
|
- else exit;
|
|
|
- if IsOK and FileName.IsEmpty then
|
|
|
- begin
|
|
|
- FileName := JStringToString(URI.getPath);
|
|
|
- end
|
|
|
- else if not IsOK then
|
|
|
- begin
|
|
|
- IsOK := SameText('content', FileScheme);
|
|
|
- if IsOK then
|
|
|
- begin
|
|
|
- IsOK := False;
|
|
|
- projection := TJavaObjectArray<JString>.Create(1);
|
|
|
- projection.Items[0] := StringToJString('_data');
|
|
|
- try
|
|
|
- cursor :=
|
|
|
-{$IF CompilerVersion >= 30.0} // >=RAD10
|
|
|
- TAndroidHelper.Context
|
|
|
-{$ELSE}
|
|
|
- SharedActivityContext
|
|
|
-{$ENDIF}
|
|
|
- .getContentResolver().query(URI, projection, selection, selectionArgs, nil);
|
|
|
- if (cursor <> nil) then
|
|
|
- begin
|
|
|
- column_index := cursor.getColumnIndexOrThrow(StringToJString('_data'));
|
|
|
- if cursor.moveToFirst then
|
|
|
- begin
|
|
|
- FileName := JStringToString(cursor.getString(column_index));
|
|
|
- IsOK := True;
|
|
|
- end;
|
|
|
- end;
|
|
|
- except
|
|
|
- IsOK := False;
|
|
|
- end;
|
|
|
- end;
|
|
|
-// if not IsOK then
|
|
|
-// begin
|
|
|
-// FileName := JStringToString(URI.getPath);
|
|
|
-// FileName := FileName.Trim;
|
|
|
-// IsOK := not FileName.IsEmpty;
|
|
|
-// if not IsOK then
|
|
|
-// begin
|
|
|
-// IsOK := FileName.IndexOf(PathDelim) <> -1;
|
|
|
-// end;
|
|
|
-// end;
|
|
|
-// end;
|
|
|
- end;
|
|
|
- if IsOK then
|
|
|
- begin
|
|
|
- FileName := FileName.Trim;
|
|
|
- IsOK := not FileName.IsEmpty;
|
|
|
- end;
|
|
|
-// if IsOK then
|
|
|
-// begin
|
|
|
-//// IsOK := FileExists(FileName);
|
|
|
-// IsOK := FileName.IndexOf(PathDelim) <> -1;
|
|
|
-// end;
|
|
|
- if Assigned(FGetFileNameCallBack1) then
|
|
|
- FGetFileNameCallBack1(IsOK, FileName);
|
|
|
- if Assigned(FGetFileNameCallBack2) then
|
|
|
- FGetFileNameCallBack2(IsOK, FileName);
|
|
|
-end;
|
|
|
-
|
|
|
-function InternalOpenFileDialog(Title, FileExtension:string;
|
|
|
- GetFileNameCallBack1: TGetFileNameListener;
|
|
|
- GetFileNameCallBack2: TGetFileNameLIsternerMethod): Boolean;
|
|
|
-var
|
|
|
- MIMEType: JString;
|
|
|
- mime: JMimeTypeMap;
|
|
|
- Intent: JIntent;
|
|
|
- IntentChooser: JIntent;
|
|
|
- sMIMEType: string;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- FGetFileNameCallBack1 := GetFileNameCallBack1;
|
|
|
- FGetFileNameCallBack2 := GetFileNameCallBack2;
|
|
|
- if FileExtension.Substring(0,1) = '.' then
|
|
|
- begin
|
|
|
- FileExtension := FileExtension.Substring(1);
|
|
|
- end;
|
|
|
- if FileExtension = '*.*' then
|
|
|
- begin
|
|
|
- FileExtension := '*/*';
|
|
|
- end;
|
|
|
- MIMEType := nil;
|
|
|
- sMIMEType := '';
|
|
|
- if FileExtension = 'file/*' then
|
|
|
- begin
|
|
|
- sMIMEType := 'file/*';
|
|
|
- end
|
|
|
- else if FileExtension = '*' then
|
|
|
- begin
|
|
|
- if TOSVersion.Check(4, 4) then
|
|
|
- begin
|
|
|
- sMIMEType := '*/*';
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- sMIMEType := 'file/*';
|
|
|
- end;
|
|
|
- end
|
|
|
- else if FileExtension = '*/*' then
|
|
|
- begin
|
|
|
- sMIMEType := '*/*';
|
|
|
- end
|
|
|
- else if FileExtension = '' then
|
|
|
- begin
|
|
|
- sMIMEType := '*/*';
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- FileExtension := AnsiLowerCase(FileExtension);
|
|
|
- //http://www.oschina.net/code/snippet_1269559_25060
|
|
|
- mime := TJMimeTypeMap.JavaClass.getSingleton;
|
|
|
- if mime <> nil then
|
|
|
- begin
|
|
|
- MIMEType := mime.getMimeTypeFromExtension(StringToJString(FileExtension));
|
|
|
- end;
|
|
|
- end;
|
|
|
- if MIMEType <> nil then
|
|
|
- begin
|
|
|
- sMIMEType := JStringToString(MIMEType).Trim;
|
|
|
- end;
|
|
|
- if sMIMEType.IsEmpty then
|
|
|
- sMIMEType := '*/*'; // File/* 有时候打不开
|
|
|
- //http://www.cnblogs.com/linlf03/archive/2013/08/19/3267732.html
|
|
|
-// if TOSVersion.Check(4, 4) then
|
|
|
-// begin
|
|
|
-// Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_OPEN_DOCUMENT);
|
|
|
-// end
|
|
|
-// else
|
|
|
- begin
|
|
|
- Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_GET_CONTENT);
|
|
|
- end;
|
|
|
- Intent.setType(StringToJString(sMIMEType));
|
|
|
- Intent.addCategory(TJIntent.JavaClass.CATEGORY_OPENABLE);
|
|
|
- IntentChooser := TJIntent.JavaClass.createChooser(Intent, StrToJCharSequence(Title));
|
|
|
- if FMessageChooserID <> 0 then
|
|
|
- TMessageManager.DefaultManager.Unsubscribe(TMessageResultNotification, FMessageChooserID);
|
|
|
- FMessageChooserID := 0;
|
|
|
- FMessageChooserID := TMessageManager.DefaultManager.SubscribeToMessage(
|
|
|
- TMessageResultNotification, HandleActivityMessageforChooser);
|
|
|
- try
|
|
|
-{$IF CompilerVersion >= 30.0} // >=RAD10
|
|
|
- TAndroidHelper.Activity
|
|
|
-{$ELSE}
|
|
|
- SharedActivity
|
|
|
-{$ENDIF}
|
|
|
- .startActivityForResult(IntentChooser, FILE_SELECT_CODE);
|
|
|
- Result := True;
|
|
|
- except
|
|
|
- raise Exception.Create(Error_NotFoundFileManager_Str);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function OpenFileDialog(Title, FileExtension:string; GetFileNameCallBack: TGetFileNameListener): Boolean;
|
|
|
-begin
|
|
|
- Result := InternalOpenFileDialog(Title, FileExtension, GetFileNameCallBack, nil);
|
|
|
-end;
|
|
|
-
|
|
|
-function OpenFileDialog(Title, FileExtension:string; GetFileNameCallBack: TGetFileNameLIsternerMethod): Boolean;
|
|
|
-begin
|
|
|
- Result := InternalOpenFileDialog(Title, FileExtension, nil, GetFileNameCallBack);
|
|
|
-end;
|
|
|
-
|
|
|
-var
|
|
|
- FExterStoragePath: string = '';
|
|
|
- FInnerStoragePath: string = '';
|
|
|
- FVolumePaths: string = '';
|
|
|
- FSDRegisteredReceiver: Boolean = False;
|
|
|
-
|
|
|
-//type
|
|
|
-// TSDBroadcastListener = class(TJavaLocal, JFMXBroadcastReceiverListener)
|
|
|
-// private
|
|
|
-// //[Weak] FTestObj: TForm1; //TForm1 是拿来测试,不是必须的。
|
|
|
-// public
|
|
|
-// constructor Create;
|
|
|
-// //看上去,下面的函数属于线程中
|
|
|
-// procedure onReceive(context: JContext; intent: JIntent); cdecl;
|
|
|
-// end;
|
|
|
-//
|
|
|
-//var
|
|
|
-// //安卓下消息3元素。
|
|
|
-// FSDBroadcastReceiver: JFMXBroadcastReceiver;
|
|
|
-// FSDIntentFilter: JIntentFilter;
|
|
|
-// FSDBroadcastListener: TSDBroadcastListener;
|
|
|
-// //你的 APP 安卓对象。
|
|
|
-// FActivity: JNativeActivity;
|
|
|
-//
|
|
|
-//
|
|
|
-//{ TSDBroadcastListener }
|
|
|
-//
|
|
|
-//constructor TSDBroadcastListener.Create;
|
|
|
-//begin
|
|
|
-// inherited Create;
|
|
|
-// InnerStoragePath := GetSDCardPath(0);
|
|
|
-// ExterStoragePath := GetSDCardPath(1);
|
|
|
-// ExterStoragePathCanRead := False;
|
|
|
-// ExterStoragePathCanWrite := False;
|
|
|
-// SDMountedMessageReceived := False;
|
|
|
-//end;
|
|
|
-//
|
|
|
-//procedure TSDBroadcastListener.onReceive(context: JContext; intent: JIntent);
|
|
|
-//var
|
|
|
-// Action,
|
|
|
-// ExternalPath,
|
|
|
-// TempStr1, TempStr2, TempStr3,
|
|
|
-// TempStr: string;
|
|
|
-// AJFile: JFile;
|
|
|
-//begin
|
|
|
-// //这里就是处理消息的地方。
|
|
|
-// Action := JStringToString(intent.getAction);
|
|
|
-// TempStr1 := JStringToString(TJIntent.JavaClass.ACTION_MEDIA_MOUNTED);
|
|
|
-// TempStr2 := JStringToString(TJIntent.JavaClass.ACTION_MEDIA_UNMOUNTED);
|
|
|
-// ExternalPath := IncludeTrailingPathDelimiter(GetExternalStoragePath);
|
|
|
-// if SameText(Action, TempStr1) or SameText(Action, TempStr2) then
|
|
|
-// begin
|
|
|
-// TempStr := JStringToString(intent.getData.getPath);// 外置设备路径
|
|
|
-// TempStr := IncludeTrailingPathDelimiter(TempStr);
|
|
|
-// if TOSVersion.Check(5) and SameFileName(TempStr, ExternalPath) then
|
|
|
-// begin
|
|
|
-// //说明内外卡交换了。这是 5.0 的特点。
|
|
|
-// InnerStoragePath := ExterStoragePath;
|
|
|
-// ExterStoragePath := TempStr;
|
|
|
-// end;
|
|
|
-// if SameFileName(TempStr, ExterStoragePath) then
|
|
|
-// begin
|
|
|
-// if SameText(Action, TempStr1) then
|
|
|
-// begin
|
|
|
-// ExterStoragePathCanRead := True;
|
|
|
-// AJFile := TJFile.JavaClass.init(
|
|
|
-// StringToJString(ExcludeTrailingPathDelimiter(TempStr)));
|
|
|
-// if AJFile <> nil then
|
|
|
-// begin
|
|
|
-// ExterStoragePathCanRead := AJFile.canRead;
|
|
|
-// ExterStoragePathCanWrite := AJFile.canWrite;
|
|
|
-// end;
|
|
|
-// SDMountedMessageReceived := True;
|
|
|
-// end;
|
|
|
-// end;
|
|
|
-// end;
|
|
|
-// TempStr1 := JStringToString(TJIntent.JavaClass.ACTION_MEDIA_REMOVED);
|
|
|
-// TempStr2 := JStringToString(TJIntent.JavaClass.ACTION_MEDIA_SHARED);
|
|
|
-// TempStr3 := JStringToString(TJIntent.JavaClass.ACTION_MEDIA_EJECT);
|
|
|
-// if SameText(Action, TempStr1) or
|
|
|
-// SameText(Action, TempStr2) or SameText(Action, TempStr3) then
|
|
|
-// begin
|
|
|
-// TempStr := JStringToString(intent.getData.getPath);// 外置设备路径
|
|
|
-// TempStr := IncludeTrailingPathDelimiter(TempStr);
|
|
|
-// if SameFileName(TempStr, ExterStoragePath) then
|
|
|
-// begin
|
|
|
-// ExterStoragePathCanRead := False;
|
|
|
-// ExterStoragePathCanWrite := False;
|
|
|
-// end;
|
|
|
-// end;
|
|
|
-//end;
|
|
|
-//
|
|
|
-//procedure RegisterSDReceiver;
|
|
|
-//begin
|
|
|
-// if FSDRegisteredReceiver then exit;
|
|
|
-// FActivity := TJNativeActivity.Wrap(PANativeActivity(System.DelphiActivity)^.clazz);
|
|
|
-// //FActivity :=
|
|
|
-//{$IF CompilerVersion >= 30.0} // >=RAD10
|
|
|
-// TAndroidHelper.Activity
|
|
|
-//{$ELSE}
|
|
|
-// SharedActivity
|
|
|
-//{$ENDIF};
|
|
|
-// FSDBroadcastListener := TSDBroadcastListener.Create;
|
|
|
-// FSDBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(FSDBroadcastListener);
|
|
|
-//
|
|
|
-// //http://blog.csdn.net/yigelangmandeshiren/article/details/8145059
|
|
|
-// FSDIntentFilter := TJIntentFilter.JavaClass.init(TJIntent.JavaClass.ACTION_MEDIA_MOUNTED);
|
|
|
-// FSDIntentFilter.setPriority(1000);// 设置最高优先级
|
|
|
-// FSDIntentFilter.addAction(TJIntent.JavaClass.ACTION_MEDIA_EJECT);
|
|
|
-// FSDIntentFilter.addAction(TJIntent.JavaClass.ACTION_MEDIA_REMOVED);
|
|
|
-// FSDIntentFilter.addAction(TJIntent.JavaClass.ACTION_MEDIA_SHARED);
|
|
|
-// FSDIntentFilter.addAction(TJIntent.JavaClass.ACTION_MEDIA_UNMOUNTED);
|
|
|
-// FSDIntentFilter.addDataScheme(StringToJString('file'));
|
|
|
-//
|
|
|
-// //注册消息接收器。别忘了 unregisterReceiver(FBroadcastReceiver);
|
|
|
-// FActivity.registerReceiver(FSDBroadcastReceiver, FSDIntentFilter);
|
|
|
-//end;
|
|
|
-//
|
|
|
-//procedure UnRegisterSDReceiver;
|
|
|
-//begin
|
|
|
-// if not FSDRegisteredReceiver then exit;
|
|
|
-// FActivity.unregisterReceiver(FSDBroadcastReceiver);
|
|
|
-// FreeAndNil(FSDBroadcastListener);
|
|
|
-// FSDBroadcastReceiver := nil;
|
|
|
-// FSDIntentFilter := nil;
|
|
|
-// FActivity := nil;
|
|
|
-//end;
|
|
|
-
|
|
|
-function GetIsExternalStorageRemovable: Boolean;
|
|
|
-begin
|
|
|
- Result := True;
|
|
|
- try
|
|
|
- Result := TJEnvironment.JavaClass.isExternalStorageRemovable;
|
|
|
- except
|
|
|
- //低版本可能发生错误。
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function GetExterStoragePath: string;
|
|
|
-//var
|
|
|
-// AJstr: JString;
|
|
|
-begin
|
|
|
- if FExterStoragePath.Trim = '' then
|
|
|
- begin
|
|
|
- FExterStoragePath := GetSDCardPath(1);
|
|
|
- if GetIsExternalStorageRemovable then
|
|
|
- begin
|
|
|
- FExterStoragePath := GetSDCardPath(0);
|
|
|
- end;
|
|
|
- end;
|
|
|
- Result := FExterStoragePath.Trim;
|
|
|
- if not DirectoryExists(ExcludeTrailingPathDelimiter(Result)) then
|
|
|
- Result := '';
|
|
|
-// AJstr := TJSystem.JavaClass.getenv(StringToJString('SECONDARY_STORAGE'));
|
|
|
-// if AJstr <> nil then
|
|
|
-// Result := IncludeTrailingPathDelimiter(JStringToString(AJstr));
|
|
|
-end;
|
|
|
-
|
|
|
-function GetInnerStoragePath: string;
|
|
|
-//var
|
|
|
-// AJstr: JString;
|
|
|
-begin
|
|
|
- if FInnerStoragePath.Trim = '' then
|
|
|
- begin
|
|
|
- FInnerStoragePath := GetSDCardPath(0);
|
|
|
- if GetIsExternalStorageRemovable then
|
|
|
- begin
|
|
|
- FInnerStoragePath := GetSDCardPath(1);
|
|
|
- end;
|
|
|
- end;
|
|
|
- Result := FInnerStoragePath.Trim;
|
|
|
- if not DirectoryExists(ExcludeTrailingPathDelimiter(Result)) then
|
|
|
- Result := '';
|
|
|
-
|
|
|
-// ExterStoragePath := GetSDCardPath(1);
|
|
|
-// AJstr := TJSystem.JavaClass.getenv(StringToJString('EXTERNAL_STORAGE'));
|
|
|
-// if AJstr <> nil then
|
|
|
-// Result := IncludeTrailingPathDelimiter(JStringToString(AJstr));
|
|
|
-end;
|
|
|
-
|
|
|
-function GetVolumePaths: string;
|
|
|
-var
|
|
|
- Sm: JStorageManager;
|
|
|
- SmNative: JObject;
|
|
|
- AList: TStrings;
|
|
|
- VolumePaths: TJavaObjectArray<JString>;
|
|
|
- I: Integer;
|
|
|
-begin
|
|
|
- Result := '';
|
|
|
- if not IsCanFindJavaMethod('getVolumePaths',
|
|
|
- '()[Ljava/lang/String;', 'android/os/storage/StorageManager') then
|
|
|
- begin
|
|
|
- //可以返回点别的。
|
|
|
- exit;
|
|
|
- end;
|
|
|
- Sm := nil;
|
|
|
- SmNative :=
|
|
|
-{$IF CompilerVersion >= 30.0} // >=RAD10
|
|
|
- TAndroidHelper.Context
|
|
|
-{$ELSE}
|
|
|
- SharedActivityContext
|
|
|
-{$ENDIF}
|
|
|
- .getSystemService(TJContext.JavaClass.STORAGE_SERVICE);
|
|
|
- if SmNative <> nil then
|
|
|
- begin
|
|
|
- Sm := TJStorageManager.Wrap((SmNative as ILocalObject).GetObjectID);
|
|
|
- end;
|
|
|
- //不打算兼容 2.X 了。
|
|
|
- if (Sm <> nil) and TOSVersion.Check(4) then
|
|
|
- begin
|
|
|
- AList := TStringList.Create;
|
|
|
- try
|
|
|
- try
|
|
|
- VolumePaths := Sm.getVolumePaths;
|
|
|
- for I := 0 to VolumePaths.Length - 1 do
|
|
|
- begin
|
|
|
- AList.Add(JStringToString(VolumePaths.Items[I]));
|
|
|
- end;
|
|
|
- except
|
|
|
- end;
|
|
|
- VolumePaths := nil;
|
|
|
- Result := AList.Text;
|
|
|
- FVolumePaths := Result;
|
|
|
- finally
|
|
|
- FreeAndNil(AList);
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-//function GetActiveMemorySize: UInt64;
|
|
|
-//var
|
|
|
-// AStringVs,
|
|
|
-// AStrings: TStringList;
|
|
|
-// TempValue: string;
|
|
|
-// ABufferedReader: JBufferedReader;
|
|
|
-// V1, V2: UInt64;
|
|
|
-//begin
|
|
|
-// Result := 0;
|
|
|
-// if FileExists('/proc/meminfo') then
|
|
|
-// begin
|
|
|
-// AStrings := TStringList.Create;
|
|
|
-// AStringVs := TStringList.Create;
|
|
|
-// try
|
|
|
-// AStrings.LineBreak := sLineBreak;
|
|
|
-// AStrings.NameValueSeparator := ':';
|
|
|
-// AStrings.Clear;
|
|
|
-// ABufferedReader := TJBufferedReader.JavaClass.init(
|
|
|
-// JReader(TJFileReader.JavaClass.init(StringToJString('/proc/meminfo'))));
|
|
|
-// repeat
|
|
|
-// TempValue := JStringToString(ABufferedReader.readLine);
|
|
|
-// if TempValue <> '' then
|
|
|
-// begin
|
|
|
-// AStrings.Add(TempValue);
|
|
|
-// end;
|
|
|
-// until (not ABufferedReader.ready);
|
|
|
-// ABufferedReader.close;
|
|
|
-// V1 := 0;
|
|
|
-// TempValue := AStrings.Values['Mapped'].Trim;
|
|
|
-// AStringVs.Clear;
|
|
|
-// AStringVs.NameValueSeparator := ' ';
|
|
|
-// AStringVs.Add(TempValue.Trim);
|
|
|
-// TempValue := AStringVs.Names[0];
|
|
|
-// V2 := StrToInt64Def(TempValue, 0);
|
|
|
-// V1 := V1 + V2;
|
|
|
-// TempValue := AStrings.Values['Inactive'].Trim;
|
|
|
-// AStringVs.Clear;
|
|
|
-// AStringVs.NameValueSeparator := ' ';
|
|
|
-// AStringVs.Add(TempValue.Trim);
|
|
|
-// TempValue := AStringVs.Names[0];
|
|
|
-// V2 := StrToInt64Def(TempValue, 0);
|
|
|
-// V1 := V1 + V2;
|
|
|
-// Result := V1 * 1024;
|
|
|
-// finally
|
|
|
-// FreeAndNil(AStringVs);
|
|
|
-// FreeAndNil(AStrings);
|
|
|
-// end;
|
|
|
-// end;
|
|
|
-// if Result = 0 then
|
|
|
-// begin
|
|
|
-// Result := GetFreeMemorySize;
|
|
|
-// end;
|
|
|
-//end;
|
|
|
-
|
|
|
-function GetScreenClientInches: Single;
|
|
|
-var
|
|
|
- x,y: Double;
|
|
|
- dm: JDisplayMetrics;
|
|
|
-begin
|
|
|
- Result := 3;
|
|
|
- dm := GetJDisplayMetrics;
|
|
|
- if dm = nil then exit;
|
|
|
- x := dm.widthPixels;
|
|
|
- y := dm.heightPixels;
|
|
|
-// x := System.Math.Power(x / dm.xdpi, 2);
|
|
|
-// y := System.Math.Power(y / dm.ydpi, 2);
|
|
|
-// Result := Sqrt(x + y);
|
|
|
- if (dm.densityDpi > dm.xdpi) and (dm.densityDpi > dm.ydpi) then
|
|
|
- begin
|
|
|
- Result := Sqrt(x * x + y * y ) / dm.densityDpi;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := Sqrt((x * x / dm.xdpi / dm.xdpi) + (y * y / dm.ydpi / dm.ydpi));
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function IsCanFindJavaClass(const NamePath: string): Boolean;
|
|
|
-var
|
|
|
- PEnv: PJNIEnv;
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- PActivity: PANativeActivity;
|
|
|
-{$ELSE}
|
|
|
- ContextClass: JNIClass;
|
|
|
-{$ENDIF}
|
|
|
- TempClass: JNIClass;
|
|
|
- AMS: MarshaledAString;
|
|
|
-begin
|
|
|
- try
|
|
|
- TempClass := nil;
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- PActivity := PANativeActivity(System.DelphiActivity);
|
|
|
- PActivity^.vm^.AttachCurrentThread(PActivity^.vm, @PEnv, nil);
|
|
|
-{$ELSE}
|
|
|
- PJavaVM(System.JavaMachine)^.AttachCurrentThread(System.JavaMachine, @PEnv, nil);
|
|
|
- ContextClass := nil;
|
|
|
- ContextClass := PEnv^.GetObjectClass(PEnv, System.JavaContext);
|
|
|
-{$ENDIF}
|
|
|
- AMS := MarshaledAString(Utf8Encode(NamePath.Trim.Replace('.', '/', [rfReplaceAll])));
|
|
|
- try
|
|
|
- TempClass := PEnv^.FindClass(PEnv, AMS);
|
|
|
- PEnv^.ExceptionClear(PEnv);
|
|
|
- Result := TempClass <> nil;
|
|
|
- finally
|
|
|
- if TempClass <> nil then
|
|
|
- PEnv^.DeleteLocalRef(PEnv, TempClass);
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
-{$ELSE}
|
|
|
- if ContextClass <> nil then
|
|
|
- PEnv^.DeleteLocalRef(PEnv, ContextClass);
|
|
|
-{$ENDIF}
|
|
|
- end;
|
|
|
- except
|
|
|
- Result := False;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function IsCanFindJavaMethod(const MethodName, Signature: string; const CalssNamePath: string = ''): Boolean;
|
|
|
-var
|
|
|
- PEnv: PJNIEnv;
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- PActivity: PANativeActivity;
|
|
|
-{$ELSE}
|
|
|
- ContextClass: JNIClass;
|
|
|
-{$ENDIF}
|
|
|
- ActivityClass: JNIClass;
|
|
|
- GetMethod: JNIMethodID;
|
|
|
- ASignature: string;
|
|
|
- AMSMethodName, AMSSignature: MarshaledAString;
|
|
|
-begin
|
|
|
- try
|
|
|
- AMSMethodName := MarshaledAString(Utf8Encode(MethodName.Trim));
|
|
|
-
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- PActivity := PANativeActivity(System.DelphiActivity);
|
|
|
- PActivity^.vm^.AttachCurrentThread(PActivity^.vm, @PEnv, nil);
|
|
|
-{$ELSE}
|
|
|
- PJavaVM(System.JavaMachine)^.AttachCurrentThread(System.JavaMachine, @PEnv, nil);
|
|
|
- ContextClass := nil;
|
|
|
- ContextClass := PEnv^.GetObjectClass(PEnv, System.JavaContext);
|
|
|
-{$ENDIF}
|
|
|
- ActivityClass := nil;
|
|
|
- try
|
|
|
- if CalssNamePath.Trim <> '' then
|
|
|
- begin
|
|
|
- ASignature := CalssNamePath.Trim.Replace('.', '/', [rfReplaceAll]);
|
|
|
- AMSSignature := MarshaledAString(Utf8Encode(ASignature));
|
|
|
- ActivityClass := PEnv^.FindClass(PEnv, AMSSignature);
|
|
|
- PEnv^.ExceptionClear(PEnv);
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- ActivityClass := PEnv^.GetObjectClass(PEnv, PActivity^.clazz);
|
|
|
-{$ELSE}
|
|
|
- ActivityClass := PEnv^.GetObjectClass(PEnv, System.JavaContext);
|
|
|
-{$ENDIF}
|
|
|
- end;
|
|
|
- if ActivityClass <> nil then
|
|
|
- begin
|
|
|
- ASignature := Signature.Trim;
|
|
|
- AMSSignature := MarshaledAString(Utf8Encode(ASignature));
|
|
|
- GetMethod := PEnv^.GetMethodID(PEnv, ActivityClass, AMSMethodName, AMSSignature);
|
|
|
- PEnv^.ExceptionClear(PEnv);
|
|
|
- Result := GetMethod <> nil;
|
|
|
- end;
|
|
|
- finally
|
|
|
- if ActivityClass <> nil then
|
|
|
- PEnv^.DeleteLocalRef(PEnv, ActivityClass);
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
-{$ELSE}
|
|
|
- if ContextClass <> nil then
|
|
|
- PEnv^.DeleteLocalRef(PEnv, ContextClass);
|
|
|
-{$ENDIF}
|
|
|
- end;
|
|
|
- except
|
|
|
- Result := False;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function IsCanFindJavaStaticMethod(const MethodName, Signature: string; const CalssNamePath: string = ''): Boolean;
|
|
|
-var
|
|
|
- PEnv: PJNIEnv;
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- PActivity: PANativeActivity;
|
|
|
-{$ELSE}
|
|
|
- ContextClass: JNIClass;
|
|
|
-{$ENDIF}
|
|
|
- ActivityClass: JNIClass;
|
|
|
- GetMethod: JNIMethodID;
|
|
|
- ASignature: string;
|
|
|
- AMSMethodName, AMSSignature: MarshaledAString;
|
|
|
-begin
|
|
|
- try
|
|
|
- AMSMethodName := MarshaledAString(Utf8Encode(MethodName.Trim));
|
|
|
-
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- PActivity := PANativeActivity(System.DelphiActivity);
|
|
|
- PActivity^.vm^.AttachCurrentThread(PActivity^.vm, @PEnv, nil);
|
|
|
-{$ELSE}
|
|
|
- PJavaVM(System.JavaMachine)^.AttachCurrentThread(System.JavaMachine, @PEnv, nil);
|
|
|
- ContextClass := nil;
|
|
|
- ContextClass := PEnv^.GetObjectClass(PEnv, System.JavaContext);
|
|
|
-{$ENDIF}
|
|
|
- ActivityClass := nil;
|
|
|
- try
|
|
|
- if CalssNamePath.Trim <> '' then
|
|
|
- begin
|
|
|
- ASignature := CalssNamePath.Trim.Replace('.', '/', [rfReplaceAll]);
|
|
|
- AMSSignature := MarshaledAString(Utf8Encode(ASignature));
|
|
|
- ActivityClass := PEnv^.FindClass(PEnv, AMSSignature);
|
|
|
- PEnv^.ExceptionClear(PEnv);
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
- ActivityClass := PEnv^.GetObjectClass(PEnv, PActivity^.clazz);
|
|
|
-{$ELSE}
|
|
|
- ActivityClass := PEnv^.GetObjectClass(PEnv, System.JavaContext);
|
|
|
-{$ENDIF}
|
|
|
- end;
|
|
|
- if ActivityClass <> nil then
|
|
|
- begin
|
|
|
- ASignature := Signature.Trim;
|
|
|
- AMSSignature := MarshaledAString(Utf8Encode(ASignature));
|
|
|
- GetMethod := PEnv^.GetStaticMethodID(PEnv, ActivityClass, AMSMethodName, AMSSignature);
|
|
|
- PEnv^.ExceptionClear(PEnv);
|
|
|
- Result := GetMethod <> nil;
|
|
|
- end;
|
|
|
- finally
|
|
|
- if ActivityClass <> nil then
|
|
|
- PEnv^.DeleteLocalRef(PEnv, ActivityClass);
|
|
|
-{$IF CompilerVersion < 30.0} // < RAD10
|
|
|
-{$ELSE}
|
|
|
- if ContextClass <> nil then
|
|
|
- PEnv^.DeleteLocalRef(PEnv, ContextClass);
|
|
|
-{$ENDIF}
|
|
|
- end;
|
|
|
- except
|
|
|
- Result := False;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-procedure UpdateAlbum(FileNames: string);
|
|
|
-var
|
|
|
- AJStrList: TJavaObjectArray<JString>;
|
|
|
- I: Integer;
|
|
|
-begin
|
|
|
- With TStringList.Create do
|
|
|
- begin
|
|
|
- try
|
|
|
- Text := FileNames;
|
|
|
- AJStrList := TJavaObjectArray<JString>.Create(Count);
|
|
|
- for I := 0 to Count - 1 do
|
|
|
- begin
|
|
|
- AJStrList.Items[I] := StringToJString(Strings[I]);
|
|
|
- end;
|
|
|
- finally
|
|
|
- Free;
|
|
|
- end;
|
|
|
- end;
|
|
|
- TJMediaScannerConnection.JavaClass.scanFile(TAndroidHelper.Context, AJStrList,
|
|
|
- nil, nil);
|
|
|
-end;
|
|
|
-
|
|
|
-function ReadFileToString(const AFileName: string): string;
|
|
|
-var
|
|
|
- AReader: JReader;
|
|
|
- ABufferedReader: JBufferedReader;
|
|
|
- TempValue: string;
|
|
|
-begin
|
|
|
- Result := '';
|
|
|
- if not FileExists(AFileName) then exit;
|
|
|
- AReader := TJFileReader.JavaClass.init(StringToJString(AFileName)) as JReader;
|
|
|
- ABufferedReader := TJBufferedReader.JavaClass.init(AReader);
|
|
|
- repeat
|
|
|
- TempValue := JStringToString(ABufferedReader.readLine);
|
|
|
- if TempValue <> '' then
|
|
|
- begin
|
|
|
- Result := Result + sLineBreak + TempValue;
|
|
|
- end;
|
|
|
- until (not ABufferedReader.ready);
|
|
|
- ABufferedReader.close;
|
|
|
-end;
|
|
|
-
|
|
|
-function ReadNoSizeFileToString(const AFileName: string): string;
|
|
|
-begin
|
|
|
- Result := '';
|
|
|
- if not FileExists(AFileName) then exit;
|
|
|
- With TFileStream.Create(AFileName, fmOpenRead) do
|
|
|
- try
|
|
|
- if Size = -1 then exit;
|
|
|
- finally
|
|
|
- Free;
|
|
|
- end;
|
|
|
- Result := ReadFileToString(AFileName);
|
|
|
-end;
|
|
|
-
|
|
|
-{$ENDIF}
|
|
|
-
|
|
|
-{$IFDEF ANDROID}
|
|
|
-
|
|
|
-function GetJniPath(MethodName, Signature: MarshaledAString): string;
|
|
|
-var
|
|
|
- PEnv: PJniEnv;
|
|
|
- ActivityClass: JNIClass;
|
|
|
- FileClass: JNIClass;
|
|
|
- GetMethod: JNIMethodID;
|
|
|
- GetPathMethod: JNIMethodID;
|
|
|
- PActivity: PANativeActivity;
|
|
|
- StrPathObject: JNIObject;
|
|
|
- FileObject: JNIObject;
|
|
|
-begin
|
|
|
-
|
|
|
- PActivity := PANativeActivity(System.DelphiActivity);
|
|
|
- PActivity^.vm^.AttachCurrentThread(PActivity^.vm, @PEnv, nil);
|
|
|
- ActivityClass := PEnv^.GetObjectClass(PEnv, PActivity^.clazz);
|
|
|
-
|
|
|
- GetMethod := PEnv^.GetMethodID(PEnv, ActivityClass, MethodName, Signature);
|
|
|
- FileObject := PEnv^.CallObjectMethodA(PEnv, PActivity^.clazz, GetMethod, PJNIValue(ArgsToJNIValues([nil])));
|
|
|
- if FileObject = nil then
|
|
|
- Exit('');
|
|
|
- FileClass := PEnv^.GetObjectClass(PEnv, FileObject);
|
|
|
-
|
|
|
- GetPathMethod := PEnv^.GetMethodID(PEnv, FileClass, 'getPath', '()Ljava/lang/String;');
|
|
|
- StrPathObject := PEnv^.CallObjectMethodA(PEnv, FileObject, GetPathMethod, PJNIValue(ArgsToJNIValues([])));
|
|
|
-
|
|
|
- Result := JNIStringToString(PEnv, StrPathObject);
|
|
|
-
|
|
|
- PEnv^.DeleteLocalRef(PEnv, StrPathObject);
|
|
|
- PEnv^.DeleteLocalRef(PEnv, FileClass);
|
|
|
- PEnv^.DeleteLocalRef(PEnv, FileObject);
|
|
|
- PEnv^.DeleteLocalRef(PEnv, ActivityClass);
|
|
|
-
|
|
|
-end;
|
|
|
-
|
|
|
-function JNIgetExternalStorageDirectory(SubPath: string): string;
|
|
|
-begin
|
|
|
-// if SubPath <> '' then
|
|
|
-// begin
|
|
|
-// Result := IncludeTrailingPathDelimiter(
|
|
|
-// GetJniPath('getExternalStorageDirectory', '()Landroid/os/Environment;')
|
|
|
-// ) + SubPath;
|
|
|
-// end
|
|
|
-// else
|
|
|
-// begin
|
|
|
-// Result := GetJniPath('getExternalStorageDirectory', '()Landroid/os/Environment;');
|
|
|
-// end;
|
|
|
-
|
|
|
- try
|
|
|
- if SubPath <> '' then
|
|
|
- begin
|
|
|
- Result := IncludeTrailingPathDelimiter(JStringToString(
|
|
|
- TJEnvironment.JavaClass.getExternalStorageDirectory.getPath)) + SubPath;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := JStringToString(TJEnvironment.JavaClass.getExternalStorageDirectory.getPath);
|
|
|
- end;
|
|
|
- except
|
|
|
- //低版本可能发生错误。
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function GetExternalStoragePath: string;
|
|
|
-begin
|
|
|
- Result := IncludeTrailingPathDelimiter(JNIgetExternalStorageDirectory(''));
|
|
|
-end;
|
|
|
-
|
|
|
-//function isPathCanWrite(const PathOrDir: string; const Default: Boolean = True): Boolean;
|
|
|
-//var
|
|
|
-// ADir: string;
|
|
|
-//begin
|
|
|
-// Result := False;
|
|
|
-// ADir := ExcludeTrailingPathDelimiter(PathOrDir);
|
|
|
-// if not DirectoryExists(ADir) then exit;
|
|
|
-// Result := True;
|
|
|
-// try
|
|
|
-////明明无权限写入,却返回 canWrite 为 True
|
|
|
-// if not TJFile.JavaClass.init(StringToJString(ADir)).canWrite then
|
|
|
-// begin
|
|
|
-// Result := False;
|
|
|
-// end;
|
|
|
-// except
|
|
|
-// Result := False;
|
|
|
-// end;
|
|
|
-//end;
|
|
|
-
|
|
|
-function isPathCanUseNow(const PathOrDir: string; const Default: Boolean = True): Boolean;
|
|
|
-var
|
|
|
- ADir: string;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- ADir := ExcludeTrailingPathDelimiter(PathOrDir);
|
|
|
- if not DirectoryExists(ADir) then exit;
|
|
|
- try
|
|
|
-// //下面的代码不能正确的区分内外 SD。
|
|
|
-// Result := TJEnvironment.JavaClass.getExternalStorageState.equals(TJEnvironment.JavaClass.MEDIA_MOUNTED);
|
|
|
-// if GetExterStoragePath.Trim = '' then exit;
|
|
|
- Result := True;
|
|
|
-// if FindJavaMethod('getStorageState',
|
|
|
-// '(Ljava/io/File;)Ljava/lang/String;', 'android/os/Environment') then
|
|
|
-// begin
|
|
|
-// // 这个接口 5.0 会死锁。还是不用了。
|
|
|
-// if not TJEnvironment.JavaClass.getStorageState(
|
|
|
-// TJFile.JavaClass.init(StringToJString(ADir))).equals(
|
|
|
-// TJEnvironment.JavaClass.MEDIA_MOUNTED) then
|
|
|
-// begin
|
|
|
-// Result := False;
|
|
|
-// end;
|
|
|
-// end
|
|
|
-// else
|
|
|
- begin
|
|
|
- if not TJFile.JavaClass.init(StringToJString(ADir)).canRead then
|
|
|
- begin
|
|
|
- Result := False;
|
|
|
- end;
|
|
|
- end;
|
|
|
- except
|
|
|
- end;
|
|
|
-end;
|
|
|
-{$ELSE}
|
|
|
-function isPathCanUseNow(const PathOrDir: string; const Default: Boolean = True): Boolean;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- if not DirectoryExists(ExcludeTrailingPathDelimiter(PathOrDir)) then exit;
|
|
|
- Result := Default;
|
|
|
-end;
|
|
|
-{$ENDIF ANDROID}
|
|
|
-
|
|
|
-function TestPathCanWrite(const PathOrDir: string): Boolean;
|
|
|
-var
|
|
|
- ATempFile,
|
|
|
- ADir: string;
|
|
|
- AHandle: THandle;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- ADir := ExcludeTrailingPathDelimiter(PathOrDir);
|
|
|
- if not DirectoryExists(ADir) then exit;
|
|
|
- repeat
|
|
|
- ATempFile := System.IOUtils.TPath.GetTempFileName;
|
|
|
- try
|
|
|
- if FileExists(ATempFile) then
|
|
|
- System.IOUtils.TFile.Delete(ATempFile);
|
|
|
- except
|
|
|
- end;
|
|
|
- ATempFile := IncludeTrailingPathDelimiter(ADir) + ExtractFileName(ATempFile);
|
|
|
- until not FileExists(ATempFile);
|
|
|
-// ATempFile := GetTempFileName(ADir);
|
|
|
-// if FileExists(ATempFile) then
|
|
|
-// begin
|
|
|
-// System.IOUtils.TFile.Delete(ATempFile);
|
|
|
-// end;
|
|
|
- try
|
|
|
- AHandle := INVALID_HANDLE_VALUE;
|
|
|
-{$IF Defined(MSWINDOWS)}
|
|
|
- AHandle := FileCreate(ATempFile, 0);
|
|
|
-{$ELSEIF Defined(POSIX)}
|
|
|
- AHandle := FileCreate(ATempFile, FileAccessRights);
|
|
|
-{$ENDIF POSIX}
|
|
|
- if AHandle = INVALID_HANDLE_VALUE then
|
|
|
- begin
|
|
|
- Result := False;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := True;
|
|
|
- FileClose(AHandle);
|
|
|
- end;
|
|
|
- except
|
|
|
- Result := False;
|
|
|
- end;
|
|
|
- if FileExists(ATempFile) then
|
|
|
- begin
|
|
|
- System.IOUtils.TFile.Delete(ATempFile);
|
|
|
- Result := True;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-//function GetTempFileName(const ATempPath: string): string;
|
|
|
-//{$IFDEF MSWINDOWS}
|
|
|
-//var
|
|
|
-// ErrCode: UINT;
|
|
|
-//begin
|
|
|
-// SetLength(Result, MAX_PATH);
|
|
|
-//
|
|
|
-// SetLastError(ERROR_SUCCESS);
|
|
|
-// ErrCode := Winapi.Windows.GetTempFileName(PChar(
|
|
|
-// IncludeTrailingPathDelimiter(ATempPath)
|
|
|
-// ), 'tmp', 0, PChar(Result)); // DO NOT LOCALIZE
|
|
|
-// if ErrCode = 0 then
|
|
|
-// raise EInOutError.Create(SysErrorMessage(GetLastError));
|
|
|
-//
|
|
|
-// SetLength(Result, StrLen(PChar(Result)));
|
|
|
-// if FileExists(Result) then
|
|
|
-// begin
|
|
|
-// System.IOUtils.TFile.Delete(Result);
|
|
|
-// end;
|
|
|
-//end;
|
|
|
-//{$ENDIF}
|
|
|
-//{$IFDEF POSIX}
|
|
|
-//var
|
|
|
-// LTempPath: TBytes;
|
|
|
-// M: TMarshaller;
|
|
|
-// LRet: MarshaledAString;
|
|
|
-//begin
|
|
|
-//// char * tempnam(const char *dir, const char *pfx);
|
|
|
-//
|
|
|
-// { Obtain a temporary file name }
|
|
|
-// // This code changed from getting the temp name from the temp path via system
|
|
|
-// // to get the temp name inside the specified temp path. We get the system temp path.
|
|
|
-//// LTempPath := TEncoding.UTF8.GetBytes(string(tmpnam(nil)));
|
|
|
-// LRet := tempnam(MarshaledAString(M.AsUTF8(
|
|
|
-// //返回的路径没有包含 ATempPath
|
|
|
-// IncludeTrailingPathDelimiter(ATempPath)
|
|
|
-// ).ToPointer),nil);
|
|
|
-// LTempPath := TEncoding.UTF8.GetBytes(string(LRet));
|
|
|
-// free(LRet);
|
|
|
-//
|
|
|
-// { Convert to UTF16 or leave blank on possible error }
|
|
|
-// if LTempPath <> nil then
|
|
|
-// Result := TEncoding.UTF8.GetString(LTempPath)
|
|
|
-// else
|
|
|
-// Result := '';
|
|
|
-//end;
|
|
|
-//{$ENDIF POSIX}
|
|
|
-
|
|
|
-
|
|
|
-{$IFDEF ANDROID}
|
|
|
-function FileSystemAttributes(const Path: string): TFileSystemAttributes;
|
|
|
-begin
|
|
|
- Result := [fsSymLink, fsCaseSensitive];
|
|
|
-// For android platform we can use the function PathConf on the same way
|
|
|
-// that is used on IOS, but the problem is that for android we only can check
|
|
|
-// _PC_2_SYMLINKS name, and that call is failing on version 2.3.3.
|
|
|
-
|
|
|
-end;
|
|
|
-{$ENDIF ANDROID}
|
|
|
-
|
|
|
-function ExpandFileNameCase2(const FileName, RootPath: string; out MatchFound: TFilenameCaseMatch): string;
|
|
|
-var
|
|
|
- SR: System.SysUtils.TSearchRec;
|
|
|
- FullPath, Name: string;
|
|
|
- Status: Integer;
|
|
|
-{$IFDEF POSIX}
|
|
|
- FoundOne: Boolean;
|
|
|
- Scans: Byte;
|
|
|
- FirstLetter, TestLetter: string;
|
|
|
-{$ENDIF POSIX}
|
|
|
-begin
|
|
|
- Result := ExpandFileName(FileName);
|
|
|
- MatchFound := mkNone;
|
|
|
-
|
|
|
- if FileName = '' then // Stop for empty strings, otherwise we risk to get info infinite loop.
|
|
|
- Exit;
|
|
|
-
|
|
|
- FullPath := ExtractFilePath(Result);
|
|
|
- Name := ExtractFileName(Result);
|
|
|
-
|
|
|
- // if FullPath is not the root directory (portable)
|
|
|
- if not SameFileName(FullPath, IncludeTrailingPathDelimiter(ExtractFileDrive(FullPath))) then
|
|
|
- begin // Does the path need case-sensitive work?
|
|
|
- Status := FindFirst(ExcludeTrailingPathDelimiter(FullPath), faAnyFile, SR);
|
|
|
- System.SysUtils.FindClose(SR); // close search before going recursive
|
|
|
- if Status <> 0 then
|
|
|
- begin
|
|
|
- if SameFileName(IncludeTrailingPathDelimiter(FullPath), IncludeTrailingPathDelimiter(RootPath)) then
|
|
|
- begin
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- FullPath := ExcludeTrailingPathDelimiter(FullPath);
|
|
|
- FullPath := ExpandFileNameCase2(FullPath, RootPath, MatchFound);
|
|
|
- if MatchFound = mkNone then
|
|
|
- Exit; // if we can't find the path, we certainly can't find the file!
|
|
|
- end;
|
|
|
- FullPath := IncludeTrailingPathDelimiter(FullPath);
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- // Path is validated / adjusted. Now for the file itself
|
|
|
- try
|
|
|
- if System.SysUtils.FindFirst(FullPath + Name, faAnyFile, SR)= 0 then // exact match on filename
|
|
|
- begin
|
|
|
- if not (MatchFound in [mkSingleMatch, mkAmbiguous]) then // path might have been inexact
|
|
|
- begin
|
|
|
- if Name = SR.Name then
|
|
|
- MatchFound := mkExactMatch
|
|
|
- else
|
|
|
- MatchFound := mkSingleMatch;
|
|
|
- end;
|
|
|
- Exit(FullPath + SR.Name);
|
|
|
- end;
|
|
|
- finally
|
|
|
- System.SysUtils.FindClose(SR);
|
|
|
- end;
|
|
|
-
|
|
|
-{$IFDEF POSIX}
|
|
|
-{ Scan the directory.
|
|
|
- To minimize the number of filenames tested, scan the directory
|
|
|
- using upper/lowercase first letter + wildcard.
|
|
|
- This results in two scans of the directory (particularly on Linux) but
|
|
|
- vastly reduces the number of times we have to perform an expensive
|
|
|
- locale-charset case-insensitive string compare. }
|
|
|
-
|
|
|
- FoundOne := False;
|
|
|
-
|
|
|
- if (fsCaseSensitive in FileSystemAttributes(FullPath)) or
|
|
|
- (fsCasePreserving in FileSystemAttributes(FullPath)) then
|
|
|
- begin
|
|
|
- // First, scan for lowercase first letter
|
|
|
- FirstLetter := AnsiLowerCase(Name[Low(string)]);
|
|
|
- for Scans := 0 to 1 do
|
|
|
- begin
|
|
|
- Status := FindFirst(FullPath + FirstLetter + '*', faAnyFile, SR);
|
|
|
- while Status = 0 do
|
|
|
- begin
|
|
|
- if AnsiSameText(SR.Name, Name) then
|
|
|
- begin
|
|
|
- if FoundOne then
|
|
|
- begin // this is the second match
|
|
|
- MatchFound := mkAmbiguous;
|
|
|
- Exit;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- FoundOne := True;
|
|
|
- Result := FullPath + SR.Name;
|
|
|
- end;
|
|
|
- end;
|
|
|
- Status := FindNext(SR);
|
|
|
- end;
|
|
|
- FindClose(SR);
|
|
|
- TestLetter := AnsiUpperCase(Name[Low(string)]);
|
|
|
- if TestLetter = FirstLetter then
|
|
|
- Break;
|
|
|
- FirstLetter := TestLetter;
|
|
|
- end;
|
|
|
-
|
|
|
- if MatchFound <> mkAmbiguous then
|
|
|
- begin
|
|
|
- if FoundOne then
|
|
|
- MatchFound := mkSingleMatch
|
|
|
- else
|
|
|
- MatchFound := mkNone;
|
|
|
- end;
|
|
|
- end;
|
|
|
-{$ENDIF POSIX}
|
|
|
-end;
|
|
|
-
|
|
|
-function BuildFileListInAPath(const Path: string; const Attr: Integer;
|
|
|
- JustFile: Boolean = False): string;
|
|
|
-var
|
|
|
- AList: TStringList;
|
|
|
-begin
|
|
|
- Result := '';
|
|
|
- AList := TStringList.Create;
|
|
|
- try
|
|
|
- BuildFileListInAPath(Path, Attr, AList, JustFile);
|
|
|
- Result := AList.Text;
|
|
|
- finally
|
|
|
- FreeAndNil(AList);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function BuildFileListInAPath(const Path: string; const Attr: Integer; const List: TStrings;
|
|
|
- JustFile: Boolean = False): Boolean;
|
|
|
-var
|
|
|
- SearchRec: TSearchRec;
|
|
|
- R: Integer;
|
|
|
-begin
|
|
|
- Assert(List <> nil);
|
|
|
- R := System.SysUtils.FindFirst(ExcludeTrailingPathDelimiter(Path), Attr, SearchRec);
|
|
|
- Result := R = 0;
|
|
|
- try
|
|
|
- if Result then
|
|
|
- begin
|
|
|
- while R = 0 do
|
|
|
- begin
|
|
|
- if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
|
|
|
- begin
|
|
|
- if ((SearchRec.Attr and faDirectory) = faDirectory) then
|
|
|
- begin
|
|
|
- if not JustFile then
|
|
|
- List.Add(SearchRec.Name);
|
|
|
- end
|
|
|
- else
|
|
|
- List.Add(SearchRec.Name);
|
|
|
- end;
|
|
|
- R := System.SysUtils.FindNext(SearchRec);
|
|
|
- end;
|
|
|
- Result := R = 0;
|
|
|
- end;
|
|
|
- finally
|
|
|
- System.SysUtils.FindClose(SearchRec);
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function faAttrToFileAttributes(
|
|
|
- const Attributes: Integer): TFileAttributes;
|
|
|
-begin
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
- Result := [];
|
|
|
-
|
|
|
- if Attributes and faReadOnly <> 0 then
|
|
|
- Include(Result, TFileAttribute.faReadOnly);
|
|
|
- if Attributes and faHidden <> 0 then
|
|
|
- Include(Result, TFileAttribute.faHidden);
|
|
|
- if Attributes and faSysFile <> 0 then
|
|
|
- Include(Result, TFileAttribute.faSystem);
|
|
|
- if Attributes and faDirectory <> 0 then
|
|
|
- Include(Result, TFileAttribute.faDirectory);
|
|
|
- if Attributes and faArchive <> 0 then
|
|
|
- Include(Result, TFileAttribute.faArchive);
|
|
|
- if Attributes and faSymLink <> 0 then
|
|
|
- Include(Result, TFileAttribute.faSymLink);
|
|
|
- if Attributes and faNormal <> 0 then
|
|
|
- Include(Result, TFileAttribute.faNormal);
|
|
|
- if Attributes and faTemporary <> 0 then
|
|
|
- Include(Result, TFileAttribute.faTemporary);
|
|
|
- if Attributes and faCompressed <> 0 then
|
|
|
- Include(Result, TFileAttribute.faCompressed);
|
|
|
- if Attributes and faEncrypted <> 0 then
|
|
|
- Include(Result, TFileAttribute.faEncrypted);
|
|
|
-{$ENDIF MSWINDOWS}
|
|
|
-{$IFDEF POSIX}
|
|
|
- Result := [];
|
|
|
- if Attributes and faDirectory <> 0 then
|
|
|
- Include(Result, TFileAttribute.faDirectory);
|
|
|
- if Attributes and faArchive <> 0 then
|
|
|
- Include(Result, TFileAttribute.faNormal);
|
|
|
- if Attributes and faSymLink <> 0 then
|
|
|
- Include(Result, TFileAttribute.faSymLink);
|
|
|
- if Attributes and faNormal <> 0 then
|
|
|
- Include(Result, TFileAttribute.faNormal);
|
|
|
-{$ENDIF POSIX}
|
|
|
-end;
|
|
|
-
|
|
|
-{$IFDEF MSWINDOWS}
|
|
|
-{$ELSE}
|
|
|
-//好像不一定有效果。
|
|
|
-function FileSetAttr(const FileName: string; Attr: Integer; FollowLink: Boolean = True): Integer;
|
|
|
-var
|
|
|
- AFileAttributes: TFileAttributes;
|
|
|
-begin
|
|
|
-// Result := faInvalid;
|
|
|
-// AFileAttributes := faAttrToFileAttributes(Attr);
|
|
|
-// TFile.SetAttributes(FileName, AFileAttributes);
|
|
|
- Result := 0;
|
|
|
-end;
|
|
|
-{$ENDIF MSWINDOWS}
|
|
|
-
|
|
|
-function DeleteTreeByEcho(const Source: string; AbortOnFailure: Boolean = False;
|
|
|
- YesToAll: Boolean = True;
|
|
|
- WaitMinSecond: Integer = DeleteDirectories_WaitMinSecond): Boolean;
|
|
|
-var
|
|
|
- Files: TStringList;
|
|
|
- LPath: string; // writable copy of Path
|
|
|
- FileName: string;
|
|
|
- I: Integer;
|
|
|
- PartialResult: Boolean;
|
|
|
- Attr: Integer;
|
|
|
- isDir: Boolean;
|
|
|
- ToDeleteDir: string;
|
|
|
- T: TDateTime;
|
|
|
- FWaitSecond, FWaitMinSecond: Integer;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- if not DirectoryExists(ExtractFileDir(Source)) then
|
|
|
- begin
|
|
|
- exit;
|
|
|
- end;
|
|
|
- if Trim(Source) = PathDelim then
|
|
|
- begin
|
|
|
- exit;
|
|
|
- end;
|
|
|
- isDir := DirectoryExists(Source);
|
|
|
- Result := True;
|
|
|
- Files := TStringList.Create;
|
|
|
- try
|
|
|
- if isDir then
|
|
|
- begin
|
|
|
- LPath := IncludeTrailingPathDelimiter(Source);
|
|
|
- ToDeleteDir := LPath + '\*.*';
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- LPath := IncludeTrailingPathDelimiter(ExtractFilePath(Source));
|
|
|
- ToDeleteDir := Source;
|
|
|
- end;
|
|
|
- BuildFileListInAPath(ToDeleteDir, faAnyFile, Files);
|
|
|
- for I := 0 to Files.Count - 1 do
|
|
|
- begin
|
|
|
- FileName := LPath + PathDelim + Files[I];
|
|
|
- PartialResult := True;
|
|
|
- // If the current file is itself a directory then recursively delete it
|
|
|
- Attr := FileGetAttr(FileName);
|
|
|
- if (Attr <> faInvalid) and ((Attr and faDirectory) <> 0) then
|
|
|
- begin
|
|
|
- PartialResult := DeleteTreeByEcho(FileName, AbortOnFailure, YesToAll,
|
|
|
- WaitMinSecond);
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- if YesToAll then
|
|
|
- begin
|
|
|
- // Set attributes to normal in case it's a readonly file
|
|
|
- PartialResult := FileSetAttr(FileName, faNormal) = 0;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- if ((Attr and faSysFile) <> 0) or ((Attr and faReadOnly) <> 0) or (Attr = faInvalid)
|
|
|
- then
|
|
|
- begin
|
|
|
- PartialResult := False;
|
|
|
- end;
|
|
|
- end;
|
|
|
- if PartialResult then
|
|
|
- PartialResult := System.SysUtils.DeleteFile(FileName); //TFile.Delete()
|
|
|
- end;
|
|
|
- if not PartialResult then
|
|
|
- begin
|
|
|
- Result := False;
|
|
|
- if AbortOnFailure then
|
|
|
- begin
|
|
|
- Break;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- finally
|
|
|
- FreeAndNil(Files);
|
|
|
- end;
|
|
|
- if Result and isDir then
|
|
|
- begin
|
|
|
- if YesToAll then
|
|
|
- begin
|
|
|
- // Finally remove the directory itself
|
|
|
- Result := FileSetAttr(LPath, faNormal or faDirectory) = 0;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Attr := FileGetAttr(LPath);
|
|
|
- if ((Attr and faSysFile) <> 0) or ((Attr and faReadOnly) <> 0) or (Attr = faInvalid) then
|
|
|
- begin
|
|
|
- Result := False;
|
|
|
- end;
|
|
|
- end;
|
|
|
- if Result then
|
|
|
- begin
|
|
|
-{$IOCHECKS OFF}
|
|
|
- RmDir(LPath);
|
|
|
- T := Now;
|
|
|
- FWaitSecond := WaitMinSecond div 1000;
|
|
|
- FWaitMinSecond := WaitMinSecond mod 1000;
|
|
|
- while DirectoryExists(LPath) do
|
|
|
- begin
|
|
|
- if T + EncodeTime(0, 0, FWaitSecond, FWaitMinSecond) < now then
|
|
|
- begin
|
|
|
- break;
|
|
|
- end;
|
|
|
- Sleep(1);
|
|
|
- end;
|
|
|
-{$IFDEF IOCHECKS_ON}
|
|
|
-{$IOCHECKS ON}
|
|
|
-{$ENDIF IOCHECKS_ON}
|
|
|
- // Result := IOResult = 0;
|
|
|
- Result := not DirectoryExists(LPath);
|
|
|
- // if not Result then
|
|
|
- // begin
|
|
|
- // ShowMessage(LPath);
|
|
|
- // end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function DeleteDirectoryByEcho(const Source: string;
|
|
|
- AbortOnFailure: Boolean = False; YesToAll: Boolean = True;
|
|
|
- WaitMinSecond: Integer = DeleteDirectories_WaitMinSecond): Boolean;
|
|
|
-var
|
|
|
- T: TDateTime;
|
|
|
- FWaitSecond, FWaitMinSecond: Integer;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- if not DirectoryExists(ExtractFileDir(Source)) then
|
|
|
- begin
|
|
|
- exit;
|
|
|
- end;
|
|
|
- if Trim(Source) = PathDelim then
|
|
|
- begin
|
|
|
- exit;
|
|
|
- end;
|
|
|
- Result := DeleteTreeByEcho(Source, AbortOnFailure, YesToAll, WaitMinSecond);
|
|
|
- if Result then
|
|
|
- begin
|
|
|
- T := Now;
|
|
|
- FWaitSecond := WaitMinSecond div 1000;
|
|
|
- FWaitMinSecond := WaitMinSecond mod 1000;
|
|
|
- while DirectoryExists(Source) do
|
|
|
- begin
|
|
|
- if T + EncodeTime(0, 0, FWaitSecond, FWaitMinSecond) < now then
|
|
|
- begin
|
|
|
- break;
|
|
|
- end;
|
|
|
- Sleep(1);
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-function GetFileNamesFromDirectory(const DirName: string; const SearchFilter: string = '*';
|
|
|
- const FileAttribs: Integer = faAnyFile; const isIncludeSubDirName: Boolean = False; const Recursion: Boolean = False;
|
|
|
- const FullName: Boolean = False): string;
|
|
|
-var
|
|
|
- SubList, FileNameList: TStrings;
|
|
|
- DirPath: string;
|
|
|
- SearchRec: TSearchRec;
|
|
|
- i: Integer;
|
|
|
-begin
|
|
|
- Result := '';
|
|
|
- if Trim(SearchFilter) = '' then
|
|
|
- begin
|
|
|
- exit;
|
|
|
- end;
|
|
|
- if DirectoryExists(DirName) then
|
|
|
- begin
|
|
|
- FileNameList := TStringList.Create;
|
|
|
- try
|
|
|
- try
|
|
|
- DirPath := IncludeTrailingPathDelimiter(DirName);
|
|
|
- // 得到该目录下指定类型文件的文件名
|
|
|
- if System.SysUtils.FindFirst(DirPath + Trim(SearchFilter), FileAttribs, SearchRec) = 0 then
|
|
|
- try
|
|
|
- repeat
|
|
|
- if isIncludeSubDirName or ((SearchRec.Attr and faDirectory) <> faDirectory) then
|
|
|
- begin
|
|
|
- if (SearchRec.Attr and faDirectory) = faDirectory then
|
|
|
- begin
|
|
|
- if (ExtractFileName(SearchRec.Name) = '.') or (ExtractFileName(SearchRec.Name) = '..') then
|
|
|
- begin
|
|
|
- Continue;
|
|
|
- end;
|
|
|
- end;
|
|
|
- if FullName then
|
|
|
- begin
|
|
|
- FileNameList.Add(ExpandFileName(SearchRec.Name));
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- FileNameList.Add(ExtractFileName(SearchRec.Name));
|
|
|
- end;
|
|
|
- end;
|
|
|
- until System.SysUtils.FindNext(SearchRec) <> 0;
|
|
|
- finally
|
|
|
- System.SysUtils.FindClose(SearchRec);
|
|
|
- end;
|
|
|
-
|
|
|
- // 递归该目录下所有子目录下的指定文件。
|
|
|
- if Recursion and (System.SysUtils.FindFirst(DirPath + '*', faDirectory, SearchRec) = 0) then
|
|
|
- try
|
|
|
- repeat
|
|
|
- if Recursion and ((SearchRec.Attr and faDirectory) = faDirectory) and
|
|
|
- (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
|
|
|
- begin
|
|
|
- Result := GetFileNamesFromDirectory(DirPath + ExtractFileName(SearchRec.Name), SearchFilter,
|
|
|
- FileAttribs, isIncludeSubDirName, Recursion, FullName);
|
|
|
- SubList := TStringList.Create;
|
|
|
- try
|
|
|
- SubList.Clear;
|
|
|
- SubList.Text := Result;
|
|
|
- if not FullName then
|
|
|
- begin
|
|
|
- for i := 0 to SubList.Count - 1 do
|
|
|
- begin
|
|
|
- SubList.Strings[i] := ExtractFileName(SearchRec.Name) + PathDelim + SubList.Strings[i];
|
|
|
- end;
|
|
|
- end;
|
|
|
- Result := '';
|
|
|
- FileNameList.AddStrings(SubList);
|
|
|
- finally
|
|
|
- FreeAndNil(SubList);
|
|
|
- end;
|
|
|
- end;
|
|
|
- until System.SysUtils.FindNext(SearchRec) <> 0;
|
|
|
- finally
|
|
|
- System.SysUtils.FindClose(SearchRec);
|
|
|
- end;
|
|
|
- Result := FileNameList.Text;
|
|
|
- except
|
|
|
- Result := '';
|
|
|
- end;
|
|
|
- finally
|
|
|
- if FileNameList <> nil then
|
|
|
- begin
|
|
|
- FreeAndNil(FileNameList);
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function GetCaseSensitiveFileName(const FileName: string; RootPath: string = ''): string;
|
|
|
-var
|
|
|
- MatchFound: TFilenameCaseMatch;
|
|
|
-begin
|
|
|
- Result := ExpandFileNameCase2(FileName, RootPath, MatchFound);
|
|
|
-end;
|
|
|
-
|
|
|
-function GetSDCardPath(Index: Integer = 0): string;
|
|
|
-begin
|
|
|
- Result := FindSDCardSubPath('', Index);
|
|
|
-end;
|
|
|
-
|
|
|
-function FindSDCardSubPath(SubPath: string; Index: Integer = 0): string;
|
|
|
-var
|
|
|
- PathDelimedSubPath: string;
|
|
|
- UnPathDelimedSubPath: string;
|
|
|
-{$IFDEF ANDROID}
|
|
|
- VolumePathList: TStrings;
|
|
|
- UsbIndex,
|
|
|
- CdRomIndex,
|
|
|
- TempVolumeIndex,
|
|
|
- I: Integer;
|
|
|
- IsFoundDir0: Boolean;
|
|
|
-{$ENDIF ANDROID}
|
|
|
-begin
|
|
|
- PathDelimedSubPath := '';
|
|
|
- UnPathDelimedSubPath := SubPath;
|
|
|
- if UnPathDelimedSubPath <> '' then
|
|
|
- begin
|
|
|
- if UnPathDelimedSubPath.Chars[0] = PathDelim then
|
|
|
- begin
|
|
|
- UnPathDelimedSubPath := UnPathDelimedSubPath.Substring(1);
|
|
|
- end;
|
|
|
- PathDelimedSubPath := PathDelim + UnPathDelimedSubPath;
|
|
|
- end;
|
|
|
-{$IFDEF ANDROID}
|
|
|
- Result := '/storage/emulated/' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- if FVolumePaths.Trim = '' then GetVolumePaths;
|
|
|
- VolumePathList := TStringList.Create;
|
|
|
- try
|
|
|
- VolumePathList.Text := FVolumePaths;
|
|
|
- if Index = 0 then
|
|
|
- begin
|
|
|
- Result := JNIgetExternalStorageDirectory(UnPathDelimedSubPath);
|
|
|
-
|
|
|
- if not DirectoryExists(Result) and (VolumePathList.Count > 0) then
|
|
|
- begin
|
|
|
- Result := VolumePathList[0];
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/emulated/' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard_ext0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard_ext' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/sdcard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard_ext0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard_ext' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/emmc' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/nand' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/flash' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/emmc' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/flash' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/flash' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/D' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/D' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/flash' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/flash' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- //last
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end
|
|
|
- else if (Index < UsbDiskStartIndex) then
|
|
|
- begin
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard' + IntToStr(Index + 1) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'sdcard' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'sdcard' + IntToStr(Index + 1) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard_ext' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard_ext' + IntToStr(Index + 1) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard' + IntToStr(Index + 1) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard_ext' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard_ext' + IntToStr(Index + 1) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) and (VolumePathList.Count > Index) then
|
|
|
- begin
|
|
|
- Result := VolumePathList[Index];
|
|
|
- if (Result.IndexOf('usbcd') >= 0) or
|
|
|
- (Result.IndexOf('usb') >= 0) or
|
|
|
- (Result.IndexOf('otg') >= 0) or
|
|
|
- (Result.IndexOf('-rw') >= 0) or
|
|
|
- (Result.IndexOf('_rw') >= 0) or
|
|
|
- (Result.IndexOf('cdrom') >= 0) or
|
|
|
- (Result.IndexOf('cd_rom') >= 0) or
|
|
|
- (Result.IndexOf('cd-rom') >= 0) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- if Index = 1 then
|
|
|
- begin
|
|
|
- if not DirectoryExists(Result) and (VolumePathList.Count = 2) then
|
|
|
- begin
|
|
|
- Result := VolumePathList[1];
|
|
|
- if (Result.IndexOf('/storage/emulated/') < 0) and
|
|
|
- (Result.IndexOf('/storage/sdcard') < 0) and
|
|
|
- (Result.IndexOf('/mnt/sdcard') < 0) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/extSdCard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/external1' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard-ext' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/ext_card' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/extsd' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/_ExternalSD' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/external_sd' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/removable_sdcard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/extSdCard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/external1' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/sdcard-ext' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/ext_card' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/extsd' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/_ExternalSD' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/external_sd' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/removable_sdcard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'tflash' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'removable_sdcard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'tflash' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'extSdCard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'external1' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'sdcard-ext' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'ext_card' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'extsd' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + '_ExternalSD' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'external_sd' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'removable_sdcard' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- //last
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/sdcard' + IntToStr(Index) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end
|
|
|
- else if (Index >= UsbDiskStartIndex) and (Index < UsbDiskStartIndex + OTGDeivceCount) then //UsbDiskStartIndex
|
|
|
- begin
|
|
|
- UsbIndex := Index - UsbDiskStartIndex;
|
|
|
- TempVolumeIndex := UsbIndex;
|
|
|
- Result := '';
|
|
|
- for I := 1 to VolumePathList.Count - 1 do
|
|
|
- begin
|
|
|
- Result := ExcludeTrailingPathDelimiter(VolumePathList[I]);
|
|
|
- if (Result.IndexOf('/storage/usb') < 0) and
|
|
|
- (Result.IndexOf('/storage/otg') < 0) and
|
|
|
- (Result.IndexOf('/mnt/otg') < 0) and
|
|
|
- (Result.IndexOf('/mnt/usb') < 0) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else if DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- if (Result.IndexOf('usbcd') >= 0) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else if (Result.IndexOf('otgcd') >= 0) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else if (TempVolumeIndex = 0) and (Result.Chars[Result.Length] in ['2'..'9']) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else if (TempVolumeIndex <> 0) and (Result.Chars[Result.Length] <> IntToStr(TempVolumeIndex)) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := Result + PathDelimedSubPath;
|
|
|
- break;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- if (Result = '') or (not DirectoryExists(Result)) then
|
|
|
- begin
|
|
|
- if UsbIndex = 0 then
|
|
|
- begin
|
|
|
- Result := '/storage/udisk' + PathDelimedSubPath;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/udisk' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'udisk' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbdisk' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbdisk' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbdisk' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbotg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbotg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbotg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbdrive' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbdrive' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbdrive' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usb' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usb' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usb' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/otg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/otg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'otg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'udisk' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usbotg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usb' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'otg' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- //index = 0
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/udisk0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/udisk0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'udisk0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbdisk0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbdisk0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbdisk0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbotg0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbotg0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbotg0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbdrive0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbdrive0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbdrive0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usb0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usb0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usb0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'udisk0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usbotg0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usb0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- //index > 0
|
|
|
- IsFoundDir0 := False;
|
|
|
- Result := GetSDCardPath(UsbDiskStartIndex);
|
|
|
- IsFoundDir0 := Result.Chars[Result.Length] = '0';
|
|
|
- if not IsFoundDir0 then
|
|
|
- begin
|
|
|
- inc(TempVolumeIndex);
|
|
|
- end;
|
|
|
- Result := '/storage/udisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/udisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'udisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbdisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbdisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbdisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbotg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbotg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbotg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbdrive' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbdrive' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbdrive' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usb' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usb' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usb' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/otg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/otg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'otg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'udisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usbotg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usb' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'otg' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- //last
|
|
|
- if (Result = '') or (not DirectoryExists(Result)) then
|
|
|
- begin
|
|
|
- if UsbIndex = 0 then
|
|
|
- begin
|
|
|
- Result := '/storage/udisk' + PathDelimedSubPath;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := '/storage/udisk' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end
|
|
|
- else if (Index >= CDROMStartIndex) and (Index < CDROMStartIndex + OTGDeivceCount) then //CDROMStartIndex
|
|
|
- begin
|
|
|
- CdRomIndex := Index - CDROMStartIndex;
|
|
|
- TempVolumeIndex := CdRomIndex;
|
|
|
- for I := 1 to VolumePathList.Count - 1 do
|
|
|
- begin
|
|
|
- Result := ExcludeTrailingPathDelimiter(VolumePathList[I]);
|
|
|
- if (Result.IndexOf('/storage/cd') < 0) and
|
|
|
- (Result.IndexOf('/mnt/cd') < 0) and
|
|
|
- (Result.IndexOf('/storage/usbcd') < 0) and
|
|
|
- (Result.IndexOf('/mnt/usbcd') < 0) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else if DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- if (TempVolumeIndex = 0) and (Result.Chars[Result.Length] in ['2'..'9']) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else if (TempVolumeIndex <> 0) and (Result.Chars[Result.Length] <> IntToStr(TempVolumeIndex)) then
|
|
|
- begin
|
|
|
- Result := '';
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := Result + PathDelimedSubPath;
|
|
|
- break;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
- if (Result = '') or (not DirectoryExists(Result)) then
|
|
|
- begin
|
|
|
- if CdRomIndex = 0 then
|
|
|
- begin
|
|
|
- Result := '/storage/cd-rom' + PathDelimedSubPath;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cd-rom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cd-rom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- Result := '/storage/media_rw' + PathDelimedSubPath;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/media_rw' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'media_rw' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- Result := '/storage/cd_rom' + PathDelimedSubPath;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cd_rom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cd_rom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbcdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbcdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbcdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/cdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'cd-rom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usbcdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'cdrom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- Result := '/storage/cd-rom' + PathDelimedSubPath;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cd-rom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cd-rom' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- //index = 0
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/cd_rom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cd_rom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cd_rom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbcdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbcdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbcdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/cdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'cd-rom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usbcdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'cdrom0' + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- //index > 0
|
|
|
- IsFoundDir0 := False;
|
|
|
- Result := GetSDCardPath(CDROMStartIndex);
|
|
|
- IsFoundDir0 := Result.Chars[Result.Length] = '0';
|
|
|
- if not IsFoundDir0 then
|
|
|
- begin
|
|
|
- inc(TempVolumeIndex);
|
|
|
- end;
|
|
|
- Result := '/storage/cd_rom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cd_rom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cd_rom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/usbcdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/usbcdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'usbcdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/storage/cdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := '/mnt/cdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := 'cdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
-
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'cd-rom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'usbcdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- if not DirectoryExists(Result) then
|
|
|
- begin
|
|
|
- Result := GetSDCardPath(0) + 'cdrom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end;
|
|
|
-
|
|
|
- //last
|
|
|
- if (Result = '') or (not DirectoryExists(Result)) then
|
|
|
- begin
|
|
|
- if CdRomIndex = 0 then
|
|
|
- begin
|
|
|
- Result := '/storage/cd-rom' + PathDelimedSubPath;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := '/storage/cd-rom' + IntToStr(TempVolumeIndex) + PathDelimedSubPath;
|
|
|
- end;
|
|
|
- end;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := JNIgetExternalStorageDirectory(UnPathDelimedSubPath);
|
|
|
- end;
|
|
|
- finally
|
|
|
- FreeAndNil(VolumePathList);
|
|
|
- end;
|
|
|
-{$ELSE}
|
|
|
- if UnPathDelimedSubPath <> '' then
|
|
|
- begin
|
|
|
- Result := IncludeTrailingPathDelimiter(
|
|
|
- System.IOUtils.TPath.GetSharedDocumentsPath) + UnPathDelimedSubPath;
|
|
|
- end
|
|
|
- else
|
|
|
- begin
|
|
|
- Result := System.IOUtils.TPath.GetSharedDocumentsPath;
|
|
|
- end;
|
|
|
-{$ENDIF ANDROID}
|
|
|
- Result := IncludeTrailingPathDelimiter(Result);
|
|
|
-end;
|
|
|
-
|
|
|
-function GetAppPath: string;
|
|
|
-begin
|
|
|
-{$IF Defined(ANDROID)}
|
|
|
- Result := ExtractFilePath(
|
|
|
- ExcludeTrailingPathDelimiter(
|
|
|
- System.IOUtils.TPath.GetHomePath));
|
|
|
-{$ELSE}
|
|
|
- Result := ExtractFilePath(ParamStr(0));
|
|
|
-{$ENDIF ANDROID}
|
|
|
- Result := IncludeTrailingPathDelimiter(Result);
|
|
|
-end;
|
|
|
-
|
|
|
-//initialization
|
|
|
-//
|
|
|
-//finalization
|
|
|
-// UnRegisterSDReceiver;
|
|
|
-
|
|
|
-end.
|