How To Check And Hang-up/reject Incoming/outgoing Calls On Android In Delphi?
Is there any solution to programmatically check and hang-up/reject incoming/outgoing calls on Android in Delphi?
Solution 1:
First, you must have own BroadcastReceiver unit - you can download it from here.
unit CSBroadcastReceiver;
interface
uses
System.Classes
,System.SysUtils
{$IFDEF ANDROID}
,Androidapi.JNI.Embarcadero
,Androidapi.JNI.GraphicsContentViewText
,Androidapi.Helpers
,Androidapi.JNIBridge
,Androidapi.JNI.JavaTypes
,Androidapi.JNI.App
{$ENDIF}
;
type
{$IFNDEF ANDROID}
JIntent = classend;
JContext = classend;
{$ENDIF}
TCSBroadcastReceiver= class;
TOnReceive = procedure (csContext: JContext; csIntent: JIntent) of object;
{$IFDEF ANDROID}
TCSListener = class(TJavaLocal, JFMXBroadcastReceiverListener)
private
FOwner: TCSBroadcastReceiver;
public
constructor Create(AOwner: TCSBroadcastReceiver);
procedure OnReceive(csContext: JContext; csIntent: JIntent); cdecl;
end;
{$ENDIF}
TCSBroadcastReceiver = class(TComponent)
private
{$IFDEF ANDROID}
FReceiver: JBroadcastReceiver;
FListener : TCSListener;
{$ENDIF}
FOnReceive: TOnReceive;
FItems: TStringList;
function GetItem(const csIndex: Integer): String;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure SendBroadcast(csValue: String);
procedure Add(csValue: String);
procedure Delete(csIndex: Integer);
procedure Clear;
procedure setResultData(data: JString);
function Remove(const csValue: String): Integer;
function First: String;
function Last: String;
function HasPermission(const csPermission: string): Boolean;
procedure RegisterReceive;
property Item[const csIndex: Integer]: string read GetItem; default;
property Items: TStringList read FItems write FItems;
published
property OnReceive: TOnReceive read FOnReceive write FOnReceive;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Classicsoft', [TCSBroadcastReceiver]);
end;
{ TCSBroadcastReceiver }
procedure TCSBroadcastReceiver.setResultData(data: Jstring);
begin
FReceiver.setResultData(data);
end;
procedure TCSBroadcastReceiver.Add(csValue: String);
{$IFDEF ANDROID}
var
Filter: JIntentFilter;
{$ENDIF}
begin
{$IFDEF ANDROID}
if (FListener = nil) or (FReceiver = nil) thenbegin
Raise Exception.Create('First use RegisterReceive!');
Exit;
end;
{$ENDIF}
if FItems <> nilthenif FItems.IndexOf(csValue) = -1thenbegin
{$IFDEF ANDROID}
filter := TJIntentFilter.Create;
filter.addAction(StringToJString(csValue));
TAndroidHelper.Context.registerReceiver(FReceiver, filter);
{$ENDIF}
FItems.Add(csValue);
end;
end;
procedure TCSBroadcastReceiver.Clear;
begin
FItems.Clear;
end;
constructor TCSBroadcastReceiver.Create(AOwner: TComponent);
begin
inherited;
FItems := TStringList.Create;
end;
procedure TCSBroadcastReceiver.Delete(csIndex: Integer);
beginif FItems <> nilthenbegin
FItems.Delete(csIndex);
{$IFDEF ANDROID}
TAndroidHelper.Activity.UnregisterReceiver(FReceiver);
RegisterReceive;
{$ENDIF}
end;
end;
destructor TCSBroadcastReceiver.Destroy;
begin
FItems.Free;
{$IFDEF ANDROID}
if FReceiver <> nilthen
TAndroidHelper.Activity.UnregisterReceiver(FReceiver);
{$ENDIF}
inherited;
end;
function TCSBroadcastReceiver.First: String;
begin
Result := FItems[0];
end;
function TCSBroadcastReceiver.GetItem(const csIndex: Integer): String;
begin
Result := FItems[csIndex];
end;
function TCSBroadcastReceiver.HasPermission(const csPermission: string): Boolean;
{$IFDEF ANDROID}
begin
Result := TAndroidHelper.Activity.checkCallingOrSelfPermission(StringToJString(csPermission)) = TJPackageManager.JavaClass.PERMISSION_GRANTED;
{$ELSE}
begin
Result := False;
{$ENDIF}
end;
function TCSBroadcastReceiver.Last: String;
begin
Result := FItems[FItems.Count];
end;
procedure TCSBroadcastReceiver.RegisterReceive;
{$IFDEF ANDROID}
var
I: Integer;
beginif FListener = nilthen
FListener := TCSListener.Create(Self);
if FReceiver = nilthen
FReceiver := TJFMXBroadcastReceiver.JavaClass.init(FListener);
if FItems <> nilthenif FItems.Count > 0thenfor I := 0 to FItems.Count -1do
Add(FItems[I]);
{$ELSE}
begin
{$ENDIF}
end;
function TCSBroadcastReceiver.Remove(const csValue: String): Integer;
begin
Result := FItems.IndexOf(csValue);
if Result > -1then
FItems.Delete(Result);
end;
procedure TCSBroadcastReceiver.SendBroadcast(csValue: String);
{$IFDEF ANDROID}
var
Inx: JIntent;
begin
Inx := TJIntent.Create;
Inx.setAction(StringToJString(csValue));
TAndroidHelper.Context.sendBroadcast(Inx);
{$ELSE}
begin
{$ENDIF}
end;
{$IFDEF ANDROID}
constructor TCSListener.Create(AOwner: TCSBroadcastReceiver);
begin
inherited Create;
FOwner := AOwner;
end;
procedure TCSListener.OnReceive(csContext: JContext; csIntent: JIntent);
beginif Assigned(FOwner.OnReceive) then
FOwner.onReceive(csContext, csIntent);
end;
{$ENDIF}
end.
Secondly, you must create your own definition of JMethod a JLang_Class - you can download it from here.
unitAndroidapi.JNI.JavaTypes.Own;interfaceusesAndroidapi.JNI.JavaTypes,Androidapi.JNIBridge;typeJOwnMethod=interface;//java.lang.reflect.MethodJOwnLang_Class=interface;//java.lang.ClassJOwnMethodClass=interface(JObjectClass)
['{C995BD27-1D77-48E5-B478-EB8E9E607020}']
end;
[JavaSignature('java/lang/reflect/Method')]
JOwnMethod=interface(JObject)
['{ED1B0770-0BD6-4D4A-B801-9D18AB92C834}']
proceduresetAccessible(flag:Boolean);cdecl;overload;functionequals(other:JObject):Boolean;cdecl;functiongetAnnotation(annotationType:JOwnLang_Class):JAnnotation;cdecl;function getAnnotations:TJavaObjectArray<JAnnotation>;cdecl;function getDeclaredAnnotations:TJavaObjectArray<JAnnotation>;cdecl;function getDeclaringClass:JOwnLang_Class;cdecl;function getDefaultValue:JObject;cdecl;function getExceptionTypes:TJavaObjectArray<JOwnLang_Class>;cdecl;function getGenericExceptionTypes:TJavaObjectArray<Jreflect_Type>;cdecl;function getGenericParameterTypes:TJavaObjectArray<Jreflect_Type>;cdecl;function getGenericReturnType:Jreflect_Type;cdecl;function getModifiers:Integer;cdecl;function getName:JString;cdecl;function getParameterAnnotations:TJavaObjectBiArray<JAnnotation>;cdecl;function getParameterTypes:TJavaObjectArray<JOwnLang_Class>;cdecl;function getReturnType:JOwnLang_Class;cdecl;function getTypeParameters:TJavaObjectArray<JTypeVariable>;cdecl;function hashCode:Integer;cdecl;functioninvoke(receiver:JObject;args:TJavaObjectArray<JObject>):JObject;cdecl;functionisAnnotationPresent(annotationType:JOwnLang_Class):Boolean;cdecl;function isBridge:Boolean;cdecl;function isSynthetic:Boolean;cdecl;function isVarArgs:Boolean;cdecl;function toGenericString:JString;cdecl;function toString:JString;cdecl;end;TJOwnMethod=class(TJavaGenericImport<JOwnMethodClass,JOwnMethod>)end;JOwnLang_ClassClass=interface(JObjectClass)
['{E1A7F20A-FD87-4D67-9469-7492FD97D55D}']
{class} functionforName(className:JString):JOwnLang_Class;cdecl;overload;
{class} functionforName(className:JString;shouldInitialize:Boolean;classLoader:JClassLoader):JOwnLang_Class;cdecl;overload;end;
[JavaSignature('java/lang/Class')]
JOwnLang_Class=interface(JObject)
['{B056EDE6-77D8-4CDD-9864-147C201FD87C}']
functionasSubclass(c:JOwnLang_Class):JOwnLang_Class;cdecl;functioncast(obj:JObject):JObject;cdecl;function desiredAssertionStatus:Boolean;cdecl;functiongetAnnotation(annotationType:JOwnLang_Class):JAnnotation;cdecl;function getAnnotations:TJavaObjectArray<JAnnotation>;cdecl;function getCanonicalName:JString;cdecl;function getClassLoader:JClassLoader;cdecl;function getClasses:TJavaObjectArray<JOwnLang_Class>;cdecl;function getComponentType:JOwnLang_Class;cdecl;function getConstructors:TJavaObjectArray<JConstructor>;cdecl;function getDeclaredAnnotations:TJavaObjectArray<JAnnotation>;cdecl;function getDeclaredClasses:TJavaObjectArray<JOwnLang_Class>;cdecl;function getDeclaredConstructors:TJavaObjectArray<JConstructor>;cdecl;functiongetDeclaredField(name:JString):JField;cdecl;function getDeclaredFields:TJavaObjectArray<JField>;cdecl;functiongetDeclaredMethod(name:JString;parameterTypes:TJavaObjectArray<JOwnLang_Class>):JOwnMethod;cdecl;function getDeclaredMethods:TJavaObjectArray<JOwnMethod>;cdecl;function getDeclaringClass:JOwnLang_Class;cdecl;function getEnclosingClass:JOwnLang_Class;cdecl;function getEnclosingConstructor:JConstructor;cdecl;function getEnclosingMethod:JOwnMethod;cdecl;function getEnumConstants:TJavaObjectArray<JObject>;cdecl;functiongetField(name:JString):JField;cdecl;function getFields:TJavaObjectArray<JField>;cdecl;function getGenericInterfaces:TJavaObjectArray<Jreflect_Type>;cdecl;function getGenericSuperclass:Jreflect_Type;cdecl;function getInterfaces:TJavaObjectArray<JOwnLang_Class>;cdecl;function getMethods:TJavaObjectArray<JOwnMethod>;cdecl;function getModifiers:Integer;cdecl;function getName:JString;cdecl;function getPackage:JPackage;cdecl;//functiongetProtectionDomain:JProtectionDomain;cdecl;//functiongetResource(resourceName:JString):JURL;cdecl;functiongetResourceAsStream(resourceName:JString):JInputStream;cdecl;function getSigners:TJavaObjectArray<JObject>;cdecl;function getSimpleName:JString;cdecl;function getSuperclass:JOwnLang_Class;cdecl;function getTypeParameters:TJavaObjectArray<JTypeVariable>;cdecl;function isAnnotation:Boolean;cdecl;functionisAnnotationPresent(annotationType:JOwnLang_Class):Boolean;cdecl;function isAnonymousClass:Boolean;cdecl;function isArray:Boolean;cdecl;functionisAssignableFrom(c:JOwnLang_Class):Boolean;cdecl;function isEnum:Boolean;cdecl;functionisInstance(object_:JObject):Boolean;cdecl;function isInterface:Boolean;cdecl;function isLocalClass:Boolean;cdecl;function isMemberClass:Boolean;cdecl;function isPrimitive:Boolean;cdecl;function isSynthetic:Boolean;cdecl;function newInstance:JObject;cdecl;function toString:JString;cdecl;end;TJOwnLang_Class=class(TJavaGenericImport<JOwnLang_ClassClass,JOwnLang_Class>)end;implementationend.
Thirdly, you must enable items PROCESS_OUTGOING_CALL and READ_PHONE_STATE in the Uses Permissions
Fourth, you must create the code for Form1:
unit Unit1;
interface
uses
System.SysUtils,
System.Types,
System.UITypes,
System.Classes,
System.Variants,
FMX.Types,
FMX.Controls,
FMX.Forms,
FMX.Graphics,
FMX.Dialogs,
FMX.Controls.Presentation,
FMX.ScrollBox,
FMX.Memo,
CSBroadcastReceiver,
Androidapi.JNI.JavaTypes.Own,
Androidapi.Jni,
AndroidApi.JNI.GraphicsContentViewText,
Androidapi.Jni.JavaTypes,
Androidapi.JNI.Os,
Androidapi.JNIBridge,
Androidapi.JNI.Telephony;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
procedure CreateBroadcastReceiver;
procedure BroadcastReceiverOnReceive(csContext: JContext; csIntent: JIntent);
procedure CheckPhoneCallState(Context: JContext; Intent: JIntent);
function KillCall(Context: JContext): Boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
BroadcastReceiver: TCSBroadcastReceiver;
implementation
uses
Androidapi.Jni.App, Androidapi.Helpers, Androidapi.Log;
{$R *.fmx}
procedure TForm1.CreateBroadcastReceiver;
begin
if not Assigned(BroadcastReceiver) then
begin
BroadcastReceiver:= TCSBroadcastReceiver.Create(nil);
BroadcastReceiver.OnReceive:= BroadcastReceiverOnReceive;
BroadcastReceiver.RegisterReceive;
BroadcastReceiver.Add('android.intent.action.PHONE_STATE');
BroadcastReceiver.Add('android.intent.action.NEW_OUTGOING_CALL');
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if Assigned(BroadcastReceiver) then
BroadcastReceiver.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateBroadcastReceiver;
end;
procedure TForm1.BroadcastReceiverOnReceive(csContext: JContext; csIntent: JIntent);
begin
CheckPhoneCallState(csContext, csIntent);
end;
procedure TForm1.CheckPhoneCallState(Context: JContext; Intent: JIntent);
var
telephonyService: JObject;
telephonyManager: JTelephonyManager;
state: JString;
incomingCallNumber: string;
outgoingCallNumber: string;
outputResult: string;
begin
outputResult:= #13#10;
telephonyService := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.TELEPHONY_SERVICE);
telephonyManager := TJTelephonyManager.Wrap((telephonyService as ILocalObject).GetObjectID);
if JStringToString(Intent.getAction).Equals('android.intent.action.PHONE_STATE') then
begin
state:= Intent.getStringExtra(TJTelephonyManager.JavaClass.EXTRA_STATE);
if state.equals(TJTelephonyManager.JavaClass.EXTRA_STATE_IDLE) then
outputResult:= outputResult + 'Phone is IDLE ' + #13#10elseif state.equals(TJTelephonyManager.JavaClass.EXTRA_STATE_RINGING) then
begin
incomingCallNumber:= JStringToString(Intent.getStringExtra(TJTelephonyManager.JavaClass.EXTRA_INCOMING_NUMBER));
if incomingCallNumber.Equals('') then
incomingCallNumber:= 'PRIVATE NUMBER';
outputResult:= outputResult + 'Phone is RINGING' + #13#10;
outputResult:= outputResult + 'Incoming call from ' + incomingCallNumber + #13#10;
if incomingCallNumber = 'xyz' then
if KillCall(Context) then
outputResult:= outputResult + 'Call was terminated' + #13#10else
outputResult:= outputResult + 'Call was not terminated' + #13#10;
end
elseif state.equals(TJTelephonyManager.JavaClass.EXTRA_STATE_OFFHOOK) then
outputResult:= outputResult + 'Phone is OFFHOOK' + #13#10;
end
elseif JStringToString(Intent.getAction).Equals('android.intent.action.NEW_OUTGOING_CALL') then
begin
outgoingCallNumber:= JStringToString(Intent.getStringExtra(TJIntent.JavaClass.EXTRA_PHONE_NUMBER));
outputResult:= outputResult + 'Outgoing call to ' + outgoingCallNumber + #13#10;
if outgoingCallNumber = 'xyz' then
begin
BroadcastReceiver.SetResultData(nil);
outputResult:= outputResult + 'Call is not allowed to ' + outgoingCallNumber + #13#10;
end;
end;
Memo1.Lines.Append(outputResult);
end;
function TForm1.KillCall(Context: JContext): Boolean;
var
telephonyService: JObject;
classTelephony: JOwnLang_Class;
methodGetITelephony: JOwnMethod;
telephonyInterface: JObject;
telephonyInterfaceClass: JOwnLang_Class;
methodEndCall: JOwnMethod;
begin
try
telephonyService:= TAndroidHelper.Context.getSystemService(TJContext.JavaClass.TELEPHONY_SERVICE);
classTelephony := TJOwnLang_Class.JavaClass.forName(telephonyService.getClass.getName);
methodGetITelephony:= classTelephony.getDeclaredMethod(StringToJString('getITelephony'), nil);
methodGetITelephony.setAccessible(True);
telephonyInterface := methodGetITelephony.invoke(telephonyService, nil);
telephonyInterfaceClass := TJOwnLang_Class.JavaClass.forName(telephonyInterface.getClass.getName);
methodEndCall:= telephonyInterfaceClass.getDeclaredMethod(StringToJString('endCall'), nil);
methodEndCall.invoke(telephonyInterface, nil);
Result:= True;
except
on E: Exception do
begin
Result := False;
end;
end;
end;
end.
Complete demo code you can download here.
Post a Comment for "How To Check And Hang-up/reject Incoming/outgoing Calls On Android In Delphi?"