{*******************************************************}
{ }
{ Helpers for Android }
{ }
{ Copyright (C) 2020 KngStr }
{ }
{ Some Code from }
{ Kastri Free of DelphiWorlds }
{ QDAC of swish }
{ Thanks }
{ }
{*******************************************************}
unit ksAndroid.Helpers;
interface
uses
System.SysUtils,
Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.App,
Androidapi.JNI.JavaTypes, Androidapi.JNI.Net;
type
TAndroidHelperEx = record
private
class function GetJActivity: JActivity; static;
class function GetJContext: JContext; static;
class function GetJActivityManager: JActivityManager; static;
public
const
ICE_CREAM_SANDWICH = 14;
ICE_CREAM_SANDWICH_MR1 = 15;
JELLY_BEAN = 16;
JELLY_BEAN_MR1 = 17;
JELLY_BEAN_MR2 = 18;
KITKAT = 19;
KITKAT_MR1 = 20;
LOLLIPOP = 21;
LOLLIPOP_MR1 = 22;
MARSHMALLOW = 23;
NOUGAT = 24;
NOUGAT_MR1 = 25;
OREO = 26;
OREO_MR1 = 27;
PIE = 28;
Q = 29;
///
/// Checks if both build and target are greater or equal to the tested value
///
class function CheckBuildAndTarget(const AValue: Integer): Boolean; static;
///
/// Returns the equivalent of "AndroidClass.class"
///
class function GetClass(const APackageClassName: string): Jlang_Class; static;
///
/// Returns the application default icon ID
///
class function GetDefaultIconID: Integer; static;
///
/// Returns a URI to the notification sound
///
class function GetDefaultNotificationSound: Jnet_Uri; static;
///
/// Returns target Sdk version
///
class function GetTargetSdkVersion: Integer; static;
///
/// Returns installed Sdk version
///
class function GetBuildSdkVersion: Integer; static;
///
/// Returns whether the activity is running foreground
///
///
/// Useful from within a service to determine whether or not the service needs to run in foreground mode
///
class function IsActivityForeground: Boolean; static;
///
/// Converts file to uri, using FileProvider if target API >= 24
///
///
/// Use this only when accessing files with an "external" URI
///
class function UriFromFile(const AFile: JFile; const AAuthority: string = ''): Jnet_Uri; overload; static;
///
/// Converts filename to uri, using FileProvider if target API >= 24
///
///
/// Use this only when accessing files with an "external" URI
///
class function UriFromFile(const AFileName: string; const AAuthority: string = ''): Jnet_Uri; overload; static;
/// Returns Java Application Context
class property Context: JContext read GetJContext;
/// Returns Java Application Activity
/// An exception will be launched if there is no activity, for example a Service
class property Activity: JActivity read GetJActivity;
/// Returns Java Application Activity Manager
class property ActivityManager: JActivityManager read GetJActivityManager;
/// Need reorder tasks permission
class procedure BringAppToFront; static;
/// Need reorder tasks permission
class procedure SendAppToBack; static;
/// Call a Java Activity
class function StartActivity(Intent: JIntent; const Code: Integer = -1): Boolean; static;
/// Returns Application package name
class function GetPackageName: string; static;
/// Returns MimeType from filename
class function GetMimeType(AFileName: string): JString; static;
/// Checks if there is at least one application capable of receiving the intent.
class function HasAssocApp(const URI: string): Boolean; overload; static;
/// Checks if there is at least one application capable of receiving the intent.
class function HasAssocApp(const Intent: JIntent): Boolean; overload; static;
/// Install an android package: xxx.apk
///
///
///
class function InstallPackage(const AFileName: string; const AAuthority: string = ''): Boolean; static;
/// Check if an application is installed
class function IsAppInstalled(const APackage: string): Boolean; static;
/// Add/Cear FLAG_KEEP_SCREEN_ON
class function KeepScreen(AOn: Boolean): Boolean; static;
end;
implementation
uses
Androidapi.JNIBridge, Androidapi.JNI.Os, Androidapi.JNI.Support,
Androidapi.JNI.Media, Androidapi.JNI.Provider, Androidapi.JNI.Webkit,
FMX.Helpers.Android, Androidapi.Helpers;
{ TAndroidHelperEx }
class procedure TAndroidHelperEx.BringAppToFront;
begin
ActivityManager.moveTaskToFront(Activity.getTaskId, TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
end;
class function TAndroidHelperEx.CheckBuildAndTarget(const AValue: Integer): Boolean;
begin
Result := (GetBuildSdkVersion >= AValue) and (GetTargetSdkVersion >= AValue);
end;
class function TAndroidHelperEx.GetBuildSdkVersion: Integer;
begin
Result := TJBuild_VERSION.JavaClass.SDK_INT;
end;
class function TAndroidHelperEx.GetClass(const APackageClassName: string): Jlang_Class;
begin
Result := TJLang_Class.JavaClass.forName(StringToJString(APackageClassName), True, Context.getClassLoader);
end;
class function TAndroidHelperEx.GetDefaultIconID: Integer;
begin
Result := Context.getApplicationInfo.icon;
end;
class function TAndroidHelperEx.GetDefaultNotificationSound: Jnet_Uri;
begin
Result := TJRingtoneManager.JavaClass.getDefaultUri(TJRingtoneManager.JavaClass.TYPE_NOTIFICATION);
end;
class function TAndroidHelperEx.GetJActivity: JActivity;
begin
Result :=
{$IF CompilerVersion > 27}
TAndroidHelper.Activity
{$ELSE}
SharedActivity
{$ENDIF}
end;
class function TAndroidHelperEx.GetJActivityManager: JActivityManager;
var
AService: JObject;
begin
AService := Context.getSystemService(TJContext.JavaClass.ACTIVITY_SERVICE);
Result := TJActivityManager.Wrap((AService as ILocalObject).GetObjectID);
end;
class function TAndroidHelperEx.GetJContext: JContext;
begin
Result :=
{$IF CompilerVersion > 27}
TAndroidHelper.Context;
{$ELSE}
SharedActivityContext;
{$ENDIF}
end;
class function TAndroidHelperEx.GetMimeType(AFileName: string): JString;
var
LExt: string;
LTypeMap: JMimeTypeMap;
begin
Result := nil;
if AFileName = '' then
Exit;
LExt := LowerCase(ExtractFileExt(AFileName));
if Length(LExt) < 2 then
Exit;
LExt := Copy(LExt, 1);
LTypeMap := TJMimeTypeMap.JavaClass.getSingleton();
if LTypeMap = nil then
Exit;
Result := LTypeMap.getMimeTypeFromExtension(StringToJString(LExt));
end;
class function TAndroidHelperEx.GetPackageName: string;
begin
Result := JStringToString(Context.getPackageName);
end;
class function TAndroidHelperEx.GetTargetSdkVersion: Integer;
var
LApplicationInfo: JApplicationInfo;
begin
LApplicationInfo := Context.getPackageManager.getApplicationInfo(Context.getPackageName, 0);
Result := LApplicationInfo.targetSdkVersion;
end;
class function TAndroidHelperEx.HasAssocApp(const Intent: JIntent): Boolean;
begin
Result := Activity.getPackageManager.queryIntentActivities(Intent,
TJPackageManager.JavaClass.MATCH_DEFAULT_ONLY).size > 0;
end;
class function TAndroidHelperEx.HasAssocApp(const URI: string): Boolean;
var
Intent: JIntent;
begin
Result := False;
Intent := TJIntent.Create;
Intent.setData(TJnet_Uri.JavaClass.parse(StringToJString(URI)));
Intent.setAction(StringToJString('android.intent.action.VIEW'));
Result := HasAssocApp(Intent);
end;
class function TAndroidHelperEx.InstallPackage(const AFileName, AAuthority: string): Boolean;
var
LIntent: JIntent;
begin
Result := False;
if Trim(AFileName) = '' then
Exit;
LIntent := TJIntent.Create;
if CheckBuildAndTarget(OREO) then
LIntent.setAction(TJIntent.JavaClass.ACTION_INSTALL_PACKAGE)
else
LIntent.setAction(TJIntent.JavaClass.ACTION_VIEW);
// 没有这个也可以安装成功,但是安装成功后的成功页面,也就是,完成/打开 会无法显示
LIntent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
LIntent.setDataAndType(UriFromFile(AFileName, AAuthority),
StringToJString('application/vnd.android.package-archive'));
LIntent.addFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION);
Result := StartActivity(LIntent);
end;
class function TAndroidHelperEx.IsActivityForeground: Boolean;
var
LService: JObject;
LRunningApps: JList;
LAppInfo: JActivityManager_RunningAppProcessInfo;
I: Integer;
begin
Result := False;
LService := Context.getSystemService(TJContext.JavaClass.ACTIVITY_SERVICE);
LRunningApps := TJActivityManager.Wrap(TAndroidHelper.JObjectToID(LService)).getRunningAppProcesses;
for I := 0 to LRunningApps.size - 1 do begin
LAppInfo := TJActivityManager_RunningAppProcessInfo.Wrap(TAndroidHelper.JObjectToID(LRunningApps.get(I)));
if LAppInfo.importance = 100 then begin
if LAppInfo.importanceReasonComponent <> nil then begin
if LAppInfo.importanceReasonComponent.getPackageName.equals(Context.getPackageName) then
Exit(True);
end
else if LRunningApps.size = 1 then
Exit(True);
end;
end;
end;
class function TAndroidHelperEx.IsAppInstalled(const APackage: string): Boolean;
begin
Result := False;
try
//只有异常是可靠的,返回值判定不对
Result := Context.getPackageManager.getPackageInfo(StringToJString(APackage),
TJPackageManager.JavaClass.GET_ACTIVITIES) = nil;
Result := True;
except
end;
end;
class function TAndroidHelperEx.KeepScreen(AOn: Boolean): Boolean;
begin
CallInUIThreadAndWaitFinishing(
procedure begin
if AOn then
SharedActivity.getWindow.addFlags(
TJWindowManager_LayoutParams.JavaClass.FLAG_KEEP_SCREEN_ON)
else
SharedActivity.getWindow.clearFlags(
TJWindowManager_LayoutParams.JavaClass.FLAG_KEEP_SCREEN_ON);
end);
end;
class procedure TAndroidHelperEx.SendAppToBack;
begin
//SharedActivityManager.moveTaskToBack(Activity.getTaskId, TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
Activity.moveTaskToBack(True);
end;
class function TAndroidHelperEx.StartActivity(Intent: JIntent; const Code: Integer): Boolean;
begin
Result := False;
//Checks if there is at least one application capable of receiving the intent.
if Activity.getPackageManager.queryIntentActivities(Intent,
TJPackageManager.JavaClass.MATCH_DEFAULT_ONLY).size > 0 then begin
if Code = -1 then
Activity.startActivity(Intent)
else
Activity.startActivityForResult(Intent, Code);
Result := True;
end;
end;
class function TAndroidHelperEx.UriFromFile(const AFile: JFile; const AAuthority: string): Jnet_Uri;
var
LAuthority: JString;
begin
if CheckBuildAndTarget(NOUGAT) then begin
if AAuthority <> '' then
LAuthority := StringToJString(AAuthority)
else
LAuthority := Context.getApplicationContext.getPackageName.concat(StringToJString('.fileprovider'));
Result := TJFileProvider.JavaClass.getUriForFile(Context, LAuthority, AFile);
end
else
Result := TJnet_uri.JavaClass.fromFile(AFile);
end;
class function TAndroidHelperEx.UriFromFile(const AFileName, AAuthority: string): Jnet_Uri;
begin
Result := UriFromFile(TJFile.JavaClass.init(StringToJString(AFileName)), AAuthority);
end;
end.