How to Hang Up Outgoing Call in Android

Can I hang up a call programmatically in android?

First, you need to declare this permission in AndroidManifest.xml

<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Then you setup a BroadcastReceiver service for android.intent.action.PHONE_STATE (incoming calls) and android.intent.action.NEW_OUTGOING_CALL (outgoing calls) by adding the following to AndroidManifest.xml

AndroidManifest.xml

<receiver android:name=".PhoneStateReceiver">
<intent-filter android:priority="0">
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>

PhoneStateReceiver.JAVA

import java.lang.reflect.Method;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;

public class PhoneStateReceiver extends BroadcastReceiver {

public static String TAG="PhoneStateReceiver";
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.PHONE_STATE")) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
Log.d(TAG,"PhoneStateReceiver**Call State=" + state);

if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
Log.d(TAG,"PhoneStateReceiver**Idle");
} else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
// Incoming call
String incomingNumber =
intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d(TAG,"PhoneStateReceiver**Incoming call " + incomingNumber);

if (!killCall(context)) { // Using the method defined earlier
Log.d(TAG,"PhoneStateReceiver **Unable to kill incoming call");
}

} else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
Log.d(TAG,"PhoneStateReceiver **Offhook");
}
} else if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
// Outgoing call
String outgoingNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d(TAG,"PhoneStateReceiver **Outgoing call " + outgoingNumber);

setResultData(null); // Kills the outgoing call

} else {
Log.d(TAG,"PhoneStateReceiver **unexpected intent.action=" + intent.getAction());
}
}

public boolean killCall(Context context) {
try {
// Get the boring old TelephonyManager
TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

// Get the getITelephony() method
Class classTelephony = Class.forName(telephonyManager.getClass().getName());
Method methodGetITelephony = classTelephony.getDeclaredMethod("getITelephony");

// Ignore that the method is supposed to be private
methodGetITelephony.setAccessible(true);

// Invoke getITelephony() to get the ITelephony interface
Object telephonyInterface = methodGetITelephony.invoke(telephonyManager);

// Get the endCall method from ITelephony
Class telephonyInterfaceClass =
Class.forName(telephonyInterface.getClass().getName());
Method methodEndCall = telephonyInterfaceClass.getDeclaredMethod("endCall");

// Invoke endCall()
methodEndCall.invoke(telephonyInterface);

} catch (Exception ex) { // Many things can go wrong with reflection calls
Log.d(TAG,"PhoneStateReceiver **" + ex.toString());
return false;
}
return true;
}

}

MainActivity.JAVA

import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

public static final int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_PHONE_STATE)) {

// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.

} else {

// No explanation needed, we can request the permission.

ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PHONE_STATE},
MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);

// MY_PERMISSIONS_REQUEST_READ_PHONE_STATE is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
}

@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_PHONE_STATE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

// permission was granted, yay!

} else {

// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}

// other 'case' lines to check for other
// permissions this app might request
}
}
}

Detecting outgoing call and call hangup event in android

You should create a BroadcastReceiver:

public class CallReciever extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_RINGING)) {

// Phone number
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);

// Ringing state
// This code will execute when the phone has an incoming call
} else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_IDLE)
|| intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK)) {

// This code will execute when the call is answered or disconnected
}

}
}

You should register you application to listen to these intents in the manifest:

<receiver android:name=".CallReciever" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>

How to check and hang-up/reject incoming/outgoing calls on Android in Delphi?

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 = class
end;
JContext = class
end;
{$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) then
begin
Raise Exception.Create('First use RegisterReceive!');
Exit;
end;
{$ENDIF}

if FItems <> nil then
if FItems.IndexOf(csValue) = -1 then
begin
{$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);
begin
if FItems <> nil then
begin
FItems.Delete(csIndex);
{$IFDEF ANDROID}
TAndroidHelper.Activity.UnregisterReceiver(FReceiver);
RegisterReceive;
{$ENDIF}
end;
end;

destructor TCSBroadcastReceiver.Destroy;
begin
FItems.Free;
{$IFDEF ANDROID}
if FReceiver <> nil then
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;
begin
if FListener = nil then
FListener := TCSListener.Create(Self);
if FReceiver = nil then
FReceiver := TJFMXBroadcastReceiver.JavaClass.init(FListener);
if FItems <> nil then
if FItems.Count > 0 then
for I := 0 to FItems.Count -1 do
Add(FItems[I]);
{$ELSE}
begin
{$ENDIF}
end;

function TCSBroadcastReceiver.Remove(const csValue: String): Integer;
begin
Result := FItems.IndexOf(csValue);
if Result > -1 then
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);
begin
if 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.

unit Androidapi.JNI.JavaTypes.Own;

interface

uses
Androidapi.JNI.JavaTypes,
Androidapi.JNIBridge;

type
JOwnMethod = interface;//java.lang.reflect.Method
JOwnLang_Class = interface;//java.lang.Class

JOwnMethodClass = interface(JObjectClass)
['{C995BD27-1D77-48E5-B478-EB8E9E607020}']
end;

[JavaSignature('java/lang/reflect/Method')]
JOwnMethod = interface(JObject)
['{ED1B0770-0BD6-4D4A-B801-9D18AB92C834}']
procedure setAccessible(flag: Boolean); cdecl; overload;

function equals(other: JObject): Boolean; cdecl;
function getAnnotation(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;
function invoke(receiver: JObject; args: TJavaObjectArray<JObject>): JObject; cdecl;
function isAnnotationPresent(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} function forName(className: JString): JOwnLang_Class; cdecl; overload;
{class} function forName(className: JString; shouldInitialize: Boolean; classLoader: JClassLoader): JOwnLang_Class; cdecl; overload;
end;

[JavaSignature('java/lang/Class')]
JOwnLang_Class = interface(JObject)
['{B056EDE6-77D8-4CDD-9864-147C201FD87C}']
function asSubclass(c: JOwnLang_Class): JOwnLang_Class; cdecl;
function cast(obj: JObject): JObject; cdecl;
function desiredAssertionStatus: Boolean; cdecl;
function getAnnotation(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;
function getDeclaredField(name: JString): JField; cdecl;
function getDeclaredFields: TJavaObjectArray<JField>; cdecl;
function getDeclaredMethod(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;
function getField(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;
//function getProtectionDomain: JProtectionDomain; cdecl;
//function getResource(resourceName: JString): JURL; cdecl;
function getResourceAsStream(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;
function isAnnotationPresent(annotationType: JOwnLang_Class): Boolean; cdecl;
function isAnonymousClass: Boolean; cdecl;
function isArray: Boolean; cdecl;
function isAssignableFrom(c: JOwnLang_Class): Boolean; cdecl;
function isEnum: Boolean; cdecl;
function isInstance(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;

implementation

end.

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#10
else if 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#10
else
outputResult:= outputResult + 'Call was not terminated' + #13#10;
end
else if state.equals(TJTelephonyManager.JavaClass.EXTRA_STATE_OFFHOOK) then
outputResult:= outputResult + 'Phone is OFFHOOK' + #13#10;
end
else if 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.



Related Topics



Leave a reply



Submit