Resources

**App** Java app to check if device meets XE5 Firemonkey prerequisites

Importing the Bluetooth adaptor API - updated 27/09/2103. Androidapi.JNI.BluetoothAdapter.pas

**App** TOOTHY - XE5 app to demo I/O to a simple Bluetooth device - source below

uToothy.pas - source I/O to a simple Bluetooth device N.B. requires Androidapi.JNI.BluetoothAdapter.pas

TOOTHY SCREEN SHOTS 1 2

This document describes how to access ANDROID SDK JAVA classes that are not already exposed in the Embarcadero XE5 September 2013 release. e.g. BLUETOOTH. If you want to access a JAVA Class that you have created with ECLIPSE/ANDROID STUDIO or access a third party package see XE5 JNI starter kit

JNI (JAVA NATIVE INTERFACE) provides a way to use a JAVA CLASS from Delphi

Templates of every SDK java class are listed with the properties, method calling conventions, and appropriate parameter types in a file called api-versions.xml that is delivered with the JAVA SDK

e.g. GpsStatus class template (semantics android.location.GpsStatus)

<class name="android/location/GpsStatus" since="3">
		<extends name="java/lang/Object" />
		<method name="<init>()V" />
		<method name="getMaxSatellites()I" />
		<method name="getSatellites()Ljava/lang/Iterable;" />
		<method name="getTimeToFirstFix()I" />
		<field name="GPS_EVENT_FIRST_FIX" />
		<field name="GPS_EVENT_SATELLITE_STATUS" />
		<field name="GPS_EVENT_STARTED" />
		<field name="GPS_EVENT_STOPPED" />
	</class>

The method getSatellites returns a type of class java.lang.Iterable signified by the "L" notation. In this extract V, I are type tags.

Java Type Tags

Java Type Delphi Type Type Name Signature
byte ShortInt JByte B
char WideChar JChar C
double Double JDouble D
float Single JFloat F
int Integer JInt I
long Int64 JLong J
short SmallInt JShort S
void N/A N/A V
boolean Boolean JBoolean Z

A leading "[" notation refers to an array. Other types are passed as Java objects e.g. JARRAY, JSTRING etc.

XE5 provides a unit Androidapi.JNIBridge unit to handle class import. For example, to create a simple interface to BLUETOOTH, proceed as follows.

  1. Extract BluetoothAdaptor class template from api-versions.xml
  2. Check documentation http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html to establish recommended method that will instantiate the object. In this case getDefaultAdapter()
  3. Create a couple of random GUID to support the interface decalarations.
  4. Define an interface to the methods you wish to use. In this case isEnabled and getName. Note the cdecl modifiers.
  5. Add the "signature" declaration [JavaSignature('android/bluetooth/BluetoothAdapter')]
  6. Add BLUETOOTH permission to manifest.xml in XE5 IDE - Project - Options - Uses Permissions

unit Androidapi.JNI.BluetoothAdapter;
 
// (c) RedTitan Technology 2013
// JNI BLUETOOTH import demo
 
interface

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes;
 
type
 
  JBluetoothAdapter = interface;
 
  JBluetoothAdapterClass = interface(JObjectClass)
  ['{05CE5465-2953-4CC3-9D9B-01D71E90F412}']
    function getDefaultAdapter: JBluetoothAdapter; cdecl;
  end;

  [JavaSignature('android/bluetooth/BluetoothAdapter')]
  JBluetoothAdapter = interface(JObject)
  ['{D5C8CAD6-E717-4B95-89F1-A6FD0861B7DB}']

    function isEnabled:Boolean; cdecl;
    function getName:JString; cdecl;
  end;
  TJBluetoothAdapter = class(TJavaGenericImport<JBluetoothAdapterClass, JBluetoothAdapter>) end;

// get Bluetooth device name and check if it is enabled
function checkBluetooth:string;

implementation


function checkBluetooth:string;
var
  x:JBluetoothAdapter;
  s:String;
begin
  x:=TJBluetoothAdapter.JavaClass.getDefaultAdapter;
  s:=jstringtostring(x.getName);

  if x.isEnabled then result:=s+'(enabled)' else result:=s+'(disabled)';
end;

end.

C:\Program Files (x86)\Embarcadero\RAD Studio\12.0\source\rtl\android
is a good place to look for other example implementations

The unit below is rewritten to add a BluetoothDevice interface. See the getBonded function code below to see how a generic JOBJECT class can be recast as a BluetoothDevice. It is not obvious!
               o:=TJBluetoothDevice.Wrap((it.next as ILocalObject).GetObjectID); // WHAT THE *(&



unit Androidapi.JNI.BluetoothAdapter;

// (c) RedTitan Technology 2013
// JNI BLUETOOTH import demo
// Note - REQUIRES - PROJECT OPTIONS - USES PERMISSIONS - BLUETOOTH

interface

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes, Classes;

type
  /////////////////////////// BluetoothDevice //////////////////////////////////
  JBluetoothDevice = interface;
  JBluetoothDeviceClass = interface(JObjectClass)
  ['{FB8F9E83-CF98-4737-B7B0-64EFB07EBE2A}']
  end;

  [JavaSignature('android/bluetooth/BluetoothDevice')]
  JBluetoothDevice = interface(JObject)
  ['{F2560E3D-D26E-4DD8-B384-43070B02FF04}']
    function getName:JString; cdecl;
    function getAddress:JString; cdecl;
  end;

  TJBluetoothDevice = class(TJavaGenericImport<JBluetoothDeviceClass, JBluetoothDevice>) end;

  /////////////////////////// BluetoothAdapter /////////////////////////////////

  JBluetoothAdapter = interface;

  JBluetoothAdapterClass = interface(JObjectClass)
  ['{05CE5465-2953-4CC3-9D9B-01D71E90F412}']
    function getDefaultAdapter: JBluetoothAdapter; cdecl;
  end;

  [JavaSignature('android/bluetooth/BluetoothAdapter')]
  JBluetoothAdapter = interface(JObject)
  ['{D5C8CAD6-E717-4B95-89F1-A6FD0861B7DB}']

    function isEnabled:Boolean; cdecl;
    function getName:JString; cdecl;
    function cancelDiscovery:Boolean;
    function checkBluetoothAddress(Address:JString):Boolean;  cdecl;
    function disable:Boolean;  cdecl;
    function enable:Boolean;  cdecl;
    function getAddress:JString;  cdecl;
    procedure closeProfileProxy(profile:Integer;BluetoothProfile:Jobject); cdecl;
    function getBondedDevices:JSet; cdecl;
  end;

  TJBluetoothAdapter = class(TJavaGenericImport<JBluetoothAdapterClass, JBluetoothAdapter>) end;

// get local Bluetooth device name and check if it is enabled
function checkBluetooth:string;

// List bonded devices
function getBonded:TStringList;

implementation

uses
  FMX.Helpers.Android;

function checkBluetooth:string;
var
  x:JBluetoothAdapter;
  s:String;
  addr:string;
begin
  x:=TJBluetoothAdapter.JavaClass.getDefaultAdapter;
  s:=jstringtostring(x.getName);
  if x.isEnabled then result:=s+'(enabled) '+jstringtostring(x.getAddress)
    else result:=s+'(disabled)';
end;

function getBonded:TStringList;
var
  x:JBluetoothAdapter;
  externalDevices:JSet;
  bonded:Tjavaobjectarray<Jobject>;
  it:Jiterator;
  o:JBluetoothDevice;
begin
  result:=TStringlist.Create;
  x:=TJBluetoothAdapter.JavaClass.getDefaultAdapter;
  externalDevices:=x.getBondedDevices;

  it:=externalDevices.iterator;

  while it.hasNext do
  begin
    o:=TJBluetoothDevice.Wrap((it.next as ILocalObject).GetObjectID);
    result.Add(jstringtostring(o.getName)+','+jstringtostring(o.getAddress))
  end;

end;

end.



© RedTitan Technology 2013