{"id":65,"date":"2014-02-08T19:03:55","date_gmt":"2014-02-08T19:03:55","guid":{"rendered":"http:\/\/www.bverhue.nl\/g2dev\/?p=65"},"modified":"2014-02-22T18:20:40","modified_gmt":"2014-02-22T18:20:40","slug":"delphi-android-usb-interface-with-the-g2","status":"publish","type":"post","link":"https:\/\/www.bverhue.nl\/g2dev\/?p=65","title":{"rendered":"Delphi Android USB Interface with the G2"},"content":{"rendered":"<p>I first tried to use Libusb to connect my Android tablet with the G2. I managed to compile the libusb sources for Android and call it from the application, only to run into the &#8220;No permissions&#8221; error on trying to open the device.<\/p>\n<p>There is no easy solution for this at the moment, other than havng to root the device and do other complex things, which very much narrows down the public who could eventually use the application.<\/p>\n<p>So I tried the other method, using the &#8220;Java native interface&#8221;, which turned out to be very easy. Here is an example application which uses this method to interface over USB.<\/p>\n<p>It involves 3 steps:<\/p>\n<ol>\n<li>Writting the JNI API header unit<\/li>\n<li>Writing the application<\/li>\n<li>Defining a device filter in the AndroidManifest.template.xml file<\/li>\n<\/ol>\n<p>There is one important requirement: <strong>the Android device must support &#8220;Host mode&#8221; and you should use a USB OTG cable to connect to the G2.<\/strong><\/p>\n<p>Host mode means that the Android device can play the role of host to the usb slave device (the G2) and the OTG cable, because of special wiring, triggers the device into host mode.<\/p>\n<p>First the API header unit for the USB functions has to be created. I used the example over here: <a title=\"here\" href=\"http:\/\/www.pclviewer.com\/android\/\">http:\/\/www.pclviewer.com\/android\/<\/a>, which\u00a0 deals with the Bluetooth interface as an example.<\/p>\n<p>I&#8217;ve not exposed all classes or methods at the moment, just the ones I needed for my application.<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">unit Androidapi.JNI.USB;\r\n\r\n\/\/ (c) B.J.H. Verhue 2014\r\n\/\/ JNI USB API converted from api-versions.xml\r\n\r\ninterface\r\nuses\r\n  Androidapi.JNIBridge,\r\n  Androidapi.JNI.JavaTypes,\r\n  Classes;\r\n\r\ntype\r\n\/\/ =============================================================================\r\n\/\/\r\n\/\/                                 UsbEndPoint\r\n\/\/\r\n\/\/ =============================================================================\r\n\r\n  JUsbEndPoint = interface;\r\n  JUsbEndPointClass = interface(JObjectClass)\r\n  ['{4B9757DB-9DF8-4E8A-B981-E318D099B0A1}']\r\n  end;\r\n\r\n  [JavaSignature('android\/hardware\/usb\/UsbEndpoint')]\r\n  JUsbEndPoint = interface(JObject)\r\n  ['{2D1BCC63-C184-41D0-A23A-78E256F8E1D4}']\r\n    function init:JUsbEndPoint; cdecl;\r\n    function getAddress:integer; cdecl;\r\n    function getAttributes:integer; cdecl;\r\n    function getDirection:integer; cdecl;\r\n    function getEndpointNumber:integer; cdecl;\r\n    function getInterval:integer; cdecl;\r\n    function getMaxPacketSize:integer; cdecl;\r\n    function getType:integer; cdecl;\r\n  end;\r\n\r\n  TJUsbEndPoint = class(TJavaGenericImport&lt;JUsbEndPointClass, JUsbEndPoint&gt;) end;\r\n\r\n\/\/ =============================================================================\r\n\/\/\r\n\/\/                                 UsbInterface\r\n\/\/\r\n\/\/ =============================================================================\r\n\r\n  JUsbInterface = interface;\r\n  JUsbInterfaceClass = interface(JObjectClass)\r\n  ['{245DC801-9BF6-4014-B84A-62F44A8C3DB9}']\r\n  end;\r\n\r\n  [JavaSignature('android\/hardware\/usb\/UsbInterface')]\r\n  JUsbInterface = interface(JObject)\r\n  ['{82D91C14-A4AA-47D7-BA6A-5B05B86F6856}']\r\n    function init:JUsbInterface; cdecl;\r\n    function getEndpoint(i : integer): JUsbEndPoint; cdecl;\r\n    function getEndpointCount: integer; cdecl;\r\n    function getId: integer; cdecl;\r\n    function getInterfaceClass: integer; cdecl;\r\n    function getInterfaceProtocol: integer; cdecl;\r\n    function getInterfaceSubclass: integer; cdecl;\r\n  end;\r\n\r\n  TJUsbInterface = class(TJavaGenericImport&lt;JUsbInterfaceClass, JUsbInterface&gt;) end;\r\n\r\n\/\/ =============================================================================\r\n\/\/\r\n\/\/                               UsbDeviceConnection\r\n\/\/\r\n\/\/ =============================================================================\r\n\r\n  JUsbDeviceConnection = interface;\r\n  JUsbDeviceConnectionClass = interface(JObjectClass)\r\n  ['{447D85BC-BA61-4BBA-A803-563071D90D85}']\r\n  end;\r\n\r\n  [JavaSignature('android\/hardware\/usb\/UsbDeviceConnection')]\r\n  JUsbDeviceConnection = interface(JObject)\r\n  ['{D613CA69-DD0E-404A-A064-828E09429145}']\r\n    function init:JUsbDeviceConnection; cdecl;\r\n    function bulkTransfer(UsbEndpoint: JUsbEndpoint; data: TJavaArray&lt;Byte&gt;; length : integer; timeout : integer): integer; cdecl;\r\n    function claimInterface(UsbInterface: JUsbInterface; ForceClaim: boolean): boolean; cdecl;\r\n    procedure close; cdecl;\r\n    function releaseInterface(UsbInterface: JUsbInterface): boolean; cdecl;\r\n  end;\r\n\r\n  TJUsbDeviceConnection = class(TJavaGenericImport&lt;JUsbDeviceConnectionClass, JUsbDeviceConnection&gt;) end;\r\n\r\n\/\/ =============================================================================\r\n\/\/\r\n\/\/                                   UsbDevice\r\n\/\/\r\n\/\/ =============================================================================\r\n\r\n  JUsbDevice = interface;\r\n  JUsbDeviceClass = interface(JObjectClass)\r\n  ['{38F968EC-5B0B-4018-A302-4DC469509254}']\r\n  end;\r\n\r\n  [JavaSignature('android\/hardware\/usb\/UsbDevice')]\r\n  JUsbDevice = interface(JObject)\r\n  ['{35B16245-52F3-409B-86BF-259F3A8F4845}']\r\n    function getProductId:integer; cdecl;\r\n    function getVendorId:integer; cdecl;\r\n    function getInterface(i: integer):JUSBInterface; cdecl;\r\n    function getInterfaceCount: integer; cdecl;\r\n  end;\r\n\r\n  TJUsbDevice = class(TJavaGenericImport&lt;JUsbDeviceClass, JUsbDevice&gt;) end;\r\n\r\n\/\/ =============================================================================\r\n\/\/\r\n\/\/                                 UsbManager\r\n\/\/\r\n\/\/ =============================================================================\r\n\r\n  JUsbManager = interface;\r\n  JUsbManagerClass = interface(JObjectClass)\r\n  ['{D4A4DDAC-EE30-4123-A0BE-76F8E95FAC55}']\r\n  end;\r\n\r\n  [JavaSignature('android\/hardware\/usb\/UsbManager')]\r\n  JUsbManager = interface(JObject)\r\n  ['{5E8A5FA6-64DA-4C90-9D52-988D66E6728E}']\r\n    function getDeviceList:JHashMap; cdecl;\r\n    function hasPermission(UsbDevice:JUsbDevice):boolean; cdecl;\r\n    function openDevice(UsbDevice:JUsbDevice):JUsbDeviceConnection; cdecl;\r\n  end;\r\n\r\n  TJUsbManager = class(TJavaGenericImport&lt;JUsbManagerClass, JUsbManager&gt;) end;\r\n\r\n\r\nimplementation\r\n\r\nend.<\/pre>\n<p>Second writing the application.\u00a0 I&#8217;ve made a simple Android application in XE5 bases on a blank mobile form.\u00a0 The application has four buttons:<\/p>\n<ol>\n<li>List devices, this lists all connected USB devices<\/li>\n<li>Open, this opens the G2 devivce, if it is found<\/li>\n<li>Message, this sends an &#8220;Init&#8221; message to the G2<\/li>\n<li>Close, this closes the device<\/li>\n<\/ol>\n<p>The messages are shown in a Memo control.<\/p>\n<p>Here is the code<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">unit UnitUSBTestJNI;\r\n\r\n\/\/ (c) B.J.H. Verhue 2014\r\n\/\/ G2 USB communication using JNI API DEMO\r\n\r\ninterface\r\n\r\nuses\r\n  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,\r\n  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,\r\n  FMX.Memo, FMX.StdCtrls,\r\n  Androidapi.JNIBridge,\r\n  Androidapi.JNI.GraphicsContentViewText,\r\n  Androidapi.JNI.JavaTypes,\r\n  Androidapi.JNI.USB;\r\n\r\ntype\r\n  \/\/ Thread for receiving messages from G2\r\n  TUSBThread = class(TThread)\r\n  private\r\n    [Weak] FUsbDeviceConnection : JUSBDeviceConnection;\r\n    [Weak] FUsbEPII : JUSBEndPoint;\r\n    [Weak] FUsbEPBI : JUSBEndPoint;\r\n    FLogMessage : string;\r\n    FBytesRead : integer;\r\n    FIBuffer,\r\n    FBBuffer : TJavaArray&lt;Byte&gt;;\r\n  protected\r\n    procedure Execute; override;\r\n  public\r\n    constructor Create( CreateSuspended: Boolean);\r\n    destructor Destroy; override;\r\n\r\n    procedure ProcessMessage;\r\n    procedure WriteLog;\r\n    procedure DumpIMessage;\r\n    procedure DumpBMessage;\r\n\r\n    property UsbDeviceConnection : JUSBDeviceConnection read FUsbDeviceConnection write FUsbDeviceConnection;\r\n    property UsbEPII : JUSBEndPoint read FUsbEPII write FUsbEPII;\r\n    property UsbEPBI : JUSBEndPoint read FUsbEPBI write FUsbEPBI;\r\n  end;\r\n\r\n  TForm1 = class(TForm)\r\n    Panel1: TPanel;\r\n    bListDevices: TButton;\r\n    Memo1: TMemo;\r\n    bOpen: TButton;\r\n    bMessage: TButton;\r\n    bClose: TButton;\r\n    procedure bListDevicesClick(Sender: TObject);\r\n    procedure bOpenClick(Sender: TObject);\r\n    procedure bCloseClick(Sender: TObject);\r\n    procedure bMessageClick(Sender: TObject);\r\n  private\r\n    FUsbActive : boolean;\r\n    FUsbThread : TUSBThread;\r\n    FUsbManager : JUSBManager;\r\n    FUsbDevice : JUSBDevice;\r\n    FUsbInterface : JUSBInterface;\r\n    FUsbEPII, FUsbEPBI, FUsbEPBO : JUSBEndPoint;\r\n    FUsbDeviceConnection : JUSBDeviceConnection;\r\n    function GetUsbActive: boolean;\r\n    procedure SetUsbActive(const Value: boolean);\r\n    procedure DumpMessage( data : TJavaArray&lt;Byte&gt;; size : integer);\r\n  public\r\n    property UsbActive : boolean read GetUsbActive write SetUsbActive;\r\n  end;\r\n\r\nvar\r\n  Form1: TForm1;\r\n\r\nimplementation\r\nuses\r\n  FMX.Helpers.Android;\r\n\r\n{$R *.fmx}\r\n\r\nfunction CrcClavia( Seed: Integer; aVal: Integer): Word;\r\nvar\r\n   i    : Integer;\r\n   aCrc : Integer;\r\n   k    : Integer;\r\nbegin\r\n  \/\/ Calculates the G2 checksum for messages\r\n\r\n   k    := ((( Seed shr 8) xor aVal) and 255) shl 8;\r\n   aCrc := 0;\r\n   for i := 1 to 8\r\n   do begin\r\n     if ( aCrc xor k) and $8000 &lt;&gt; 0\r\n     then aCrc := ( aCrc shl 1) xor $1021\r\n     else aCrc := aCrc shl 1;\r\n     k := k shl 1;\r\n   end;\r\n   Result := (( Seed shl 8) xor aCrc) and $ffff;\r\nend;\r\n\r\nprocedure TForm1.bListDevicesClick(Sender: TObject);\r\nvar JavaObject : JObject;\r\n    DeviceList : JHashMap;\r\n    Device : JUSBDevice;\r\n    i : Jiterator;\r\n    s : JString;\r\nbegin\r\n  \/\/ Device discovery...\r\n\r\n  \/\/ Get pointer to UsbManager\r\n  JavaObject := SharedActivityContext.getSystemService(TJContext.JavaClass.USB_SERVICE);\r\n  FUsbManager := TJUSBManager.Wrap((JavaObject as ILocalObject).GetObjectID);\r\n\r\n  \/\/ Get a list of connected slave devices\r\n  DeviceList := FUsbManager.getDeviceList;\r\n  s := DeviceList.toString;\r\n  Memo1.Lines.Add(jstringtostring(s));\r\n\r\n  \/\/ Get pointer to G2 Device\r\n  FUsbDevice := nil;\r\n  i := DeviceList.values.iterator;\r\n  while i.hasNext do begin\r\n    Device := TJUSBDevice.Wrap((i.next as ILocalObject).GetObjectID);\r\n    if (Device.getVendorId = 4092) and (Device.getProductId = 2) then\r\n      FUsbDevice := Device;\r\n    Memo1.Lines.Add('VendorID ' + IntToStr(Device.getVendorId) + ', ProductID ' + IntToStr(Device.getProductId));\r\n  end;\r\n\r\n  if assigned(FUsbDevice) then\r\n    bOpen.Enabled := assigned(FUsbDevice);\r\nend;\r\n\r\nprocedure TForm1.bCloseClick(Sender: TObject);\r\nbegin\r\n  if UsbActive then\r\n    UsbActive := False;\r\nend;\r\n\r\nprocedure TForm1.bMessageClick(Sender: TObject);\r\nvar bytes_written, size, i : integer;\r\n    crc : Word;\r\n    Buffer : TJavaArray&lt;Byte&gt;;\r\nbegin\r\n  \/\/ Send &quot;Init&quot; message to G2\r\n\r\n  if assigned(FUsbDeviceConnection) then begin\r\n\r\n    Buffer := TJavaArray&lt;Byte&gt;.Create(5);\r\n    try\r\n      Size := 1 + 2 + 2;\r\n\r\n      Buffer.Items[0] := size div 256;\r\n      Buffer.Items[1] := size mod 256;\r\n      Buffer.Items[2] := $80;\r\n\r\n      \/\/ Calc CRC\r\n      Crc := 0;\r\n      i := 2;\r\n      while i &lt; (Size-2) do begin\r\n        Crc := CrcClavia(Crc, Buffer.Items[i]);\r\n        inc(i);\r\n      end;\r\n\r\n      Buffer.Items[3] := crc div 256;\r\n      Buffer.Items[4] := crc mod 256;\r\n\r\n      bytes_written := FUsbDeviceConnection.bulkTransfer(FUsbEPBO, Buffer, Size, 100);\r\n    finally\r\n      Buffer.Free;\r\n    end;\r\n  end;\r\nend;\r\n\r\nprocedure TForm1.bOpenClick(Sender: TObject);\r\nbegin\r\n  UsbActive := True;\r\nend;\r\n\r\nprocedure TForm1.DumpMessage(data: TJavaArray&lt;Byte&gt;; size : integer);\r\nvar p, i, c : integer;\r\n    char_line, line : string;\r\nbegin\r\n  \/\/ Dump message in HEX and Char values\r\n\r\n  Memo1.BeginUpdate;\r\n  try\r\n    c := 0;\r\n    i := 0;\r\n    p := 0;\r\n    line := '';\r\n    char_line := '';;\r\n    while (i&lt;size) do begin\r\n      if c &lt; 16 then begin\r\n        line := line + IntToHex(data.Items[i], 2) + ' ';\r\n        if data.Items[i] &gt;= 32 then\r\n          char_line := char_line + chr(data.Items[i])\r\n        else\r\n          char_line := char_line + '.';\r\n        inc(c);\r\n        inc(i);\r\n      end else begin\r\n        Memo1.Lines.Add(IntToHex(p, 6) + ' - ' + line + ' ' + char_line);\r\n        p := i;\r\n        c := 0;\r\n        line := '';\r\n        char_line := '';\r\n      end;\r\n    end;\r\n    if c &lt;&gt; 0 then\r\n      Memo1.Lines.Add(IntToHex(p, 6) + ' - ' + line + stringofchar(' ', 16*3 - Length(line) + 1) + char_line);\r\n  finally\r\n    Memo1.EndUpdate;\r\n  end;\r\nend;\r\n\r\nfunction TForm1.GetUsbActive: boolean;\r\nbegin\r\n  result := FUsbActive;\r\nend;\r\n\r\nprocedure TForm1.SetUsbActive(const Value: boolean);\r\nbegin\r\n  if Value then begin\r\n\r\n    \/\/ Activate the USB inteface with G2\r\n\r\n    \/\/ Get interface\r\n    Memo1.Lines.Add('# Interfaces ' + IntToStr(FUsbDevice.getInterfaceCount));\r\n\r\n    FUsbInterface := FUsbDevice.getInterface(0);\r\n    Memo1.Lines.Add('# Endpoints ' + IntToStr(FUsbInterface.getEndpointCount));\r\n\r\n    \/\/ Get 3 endpoints\r\n    FUsbEPII := FUsbInterface.getEndpoint(0);\r\n    Memo1.Lines.Add('Endpoint ' + IntToStr(FUsbEPII.getEndpointNumber));\r\n\r\n    FUsbEPBI := FUsbInterface.getEndpoint(1);\r\n    Memo1.Lines.Add('Endpoint ' + IntToStr(FUsbEPBI.getEndpointNumber));\r\n\r\n    FUsbEPBO := FUsbInterface.getEndpoint(2);\r\n    Memo1.Lines.Add('Endpoint ' + IntToStr(FUsbEPBO.getEndpointNumber));\r\n\r\n    \/\/ Check permisions\r\n    if FUsbManager.hasPermission(FUsbDevice) then begin\r\n      Memo1.Lines.Add('Permissions o.k.');\r\n    end else begin\r\n      raise Exception.Create('No permission...');\r\n    end;\r\n\r\n    \/\/ Open device\r\n    FUsbDeviceConnection := FUsbManager.openDevice(FUsbDevice);\r\n    if not assigned( FUsbDeviceConnection) then\r\n      raise Exception.Create('Failed to open device.');\r\n\r\n    if not FUsbDeviceConnection.claimInterface(FUsbInterface, True) then\r\n      raise Exception.Create('Failed to claim interface.');\r\n\r\n    FUsbActive := Value;\r\n\r\n    \/\/ Start listening thread\r\n    FUsbThread := TUsbThread.Create(True);\r\n    FUsbThread.FUsbDeviceConnection := FUsbDeviceConnection;\r\n    FUsbThread.FUsbEPII := FUsbEPII;\r\n    FUsbThread.FUsbEPBI := FUsbEPBI;\r\n    FUsbThread.Start;\r\n  end else begin\r\n\r\n    \/\/ Deactivate the USB connection\r\n\r\n    FUsbActive := Value;\r\n\r\n    if assigned(FUsbDeviceConnection) then begin\r\n\r\n      \/\/ Release interface\r\n      if not FUsbDeviceConnection.releaseInterface(FUsbInterface) then\r\n        Memo1.Lines.Add('Failed to release the interface');\r\n\r\n      \/\/ Close device and free the thread\r\n      if assigned(FUsbThread) then begin\r\n        FUsbThread.Terminate;\r\n        FUsbDeviceConnection.close;\r\n        FUsbThread.DisposeOf;\r\n      end else\r\n        FUsbDeviceConnection.close;\r\n\r\n      Memo1.Lines.Add('Device is closed');\r\n    end;\r\n  end;\r\nend;\r\n\r\n{ TUSBThread }\r\n\r\nconstructor TUsbThread.Create( CreateSuspended: Boolean);\r\nbegin\r\n  FreeOnTerminate := False;\r\n  inherited;\r\n\r\n  FIBuffer := TJavaArray&lt;Byte&gt;.Create(16);\r\n  FBBuffer := TJavaArray&lt;Byte&gt;.Create(8192);\r\nend;\r\n\r\ndestructor TUsbThread.Destroy;\r\nbegin\r\n\r\n  FBBuffer.Free;\r\n  FIBuffer.Free;\r\nend;\r\n\r\nprocedure TUsbThread.Execute;\r\nvar size : integer;\r\nbegin\r\n  FLogMessage := 'Thread started.';\r\n  synchronize(WriteLog);\r\n\r\n  \/\/ The G2 sends first a short message over the interrupt endpoint of max 16 bytes\r\n  \/\/ This may be followed by a longer message (extended message)\r\n\r\n  while assigned(FUsbDeviceConnection) and (not Terminated) do begin\r\n    FBytesRead := FUsbDeviceConnection.bulkTransfer(FUsbEPII, FIBuffer, 16, 0);\r\n\r\n    if FBytesRead &gt; 0 then begin\r\n\r\n      synchronize(DumpIMessage);\r\n\r\n      if FIBuffer.Items[0] and $f = 1 then begin\r\n        \/\/ Extended message\r\n        size := (FIBuffer.Items[1] shl 8) or FIBuffer.Items[2];\r\n\r\n        FLogMessage := 'Extended message, size ' + IntToStr(size);\r\n        synchronize(WriteLog);\r\n\r\n        FBytesRead := FUsbDeviceConnection.bulkTransfer(FUsbEPBI, FBBuffer, size, 0);\r\n\r\n        FLogMessage := 'Extended message, bytes read ' + IntToStr(FBytesRead);\r\n        synchronize(WriteLog);\r\n\r\n        synchronize(DumpBMessage);\r\n      end else begin\r\n        \/\/ Embedded message\r\n      end;\r\n    end;\r\n    sleep(10)\r\n  end;\r\n  FLogMessage := 'Thread terminated.';\r\n  synchronize(WriteLog);\r\nend;\r\n\r\nprocedure TUsbThread.ProcessMessage;\r\nbegin\r\n  \/\/ Do something with the message...\r\nend;\r\n\r\nprocedure TUsbThread.WriteLog;\r\nbegin\r\n  Form1.Memo1.Lines.Add(FLogMessage);\r\nend;\r\n\r\nprocedure TUsbThread.DumpIMessage;\r\nbegin\r\n  Form1.DumpMessage(FIBuffer, FBytesRead);\r\nend;\r\n\r\nprocedure TUsbThread.DumpBMessage;\r\nbegin\r\n  Form1.DumpMessage(FBBuffer, FBytesRead);\r\nend;\r\n\r\nend.<\/pre>\n<p>&nbsp;<\/p>\n<p>Finally we have to define a device filter in the &#8220;AndroidManifest.template.xml&#8221; file. This ensures that you get the necessary permissions for opening the device. Also, this enables automatic launch of the application when you plug in the device in your Android tablet!<\/p>\n<p>First you have to make a little xml file, containing the vendor id and product id of the device. In case of the G2 synth, this file looks like this:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\r\n&lt;resources&gt;\r\n    &lt;usb-device vendor-id=&quot;4092&quot; product-id=&quot;2&quot; class=&quot;0&quot; subclass=&quot;0&quot; protocol=&quot;0&quot; \/&gt;\r\n&lt;\/resources&gt;<\/pre>\n<p>Save this file as &#8220;device_filter.xml&#8221; and add it to the project.<\/p>\n<p>You also have to deploy this file to the Android device, so put it into the Deployment manager, with remote path &#8220;res\\xml&#8221;.<\/p>\n<p><a href=\"http:\/\/www.bverhue.nl\/g2dev\/wp-content\/uploads\/device_filter_xml_deploy.png\"><img loading=\"lazy\" class=\"alignnone size-medium wp-image-76\" alt=\"device_filter_xml_deploy\" src=\"http:\/\/www.bverhue.nl\/g2dev\/wp-content\/uploads\/device_filter_xml_deploy-300x77.png\" width=\"300\" height=\"77\" srcset=\"https:\/\/www.bverhue.nl\/g2dev\/wp-content\/uploads\/device_filter_xml_deploy-300x77.png 300w, https:\/\/www.bverhue.nl\/g2dev\/wp-content\/uploads\/device_filter_xml_deploy-624x160.png 624w, https:\/\/www.bverhue.nl\/g2dev\/wp-content\/uploads\/device_filter_xml_deploy.png 932w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Next edit the file &#8220;AndroidManifest.template.xml&#8221; which should be in your project folder after compiling the application.<\/p>\n<p>Put in<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">&lt;meta-data android:name=&quot;android.hardware.usb.action.USB_DEVICE_ATTACHED&quot;\r\n                android:resource=&quot;@xml\/device_filter&quot; \/&gt;<\/pre>\n<p>As a child in the &#8220;activity&#8221; element, and put<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">&lt;action android:name=&quot;android.hardware.usb.action.USB_DEVICE_ATTACHED&quot; \/&gt;<\/pre>\n<p>As a child to the &#8220;intent-filter&#8221; element. So the dile should look something like this:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;!-- BEGIN_INCLUDE(manifest) --&gt;\r\n&lt;manifest xmlns:android=&quot;http:\/\/schemas.android.com\/apk\/res\/android&quot;\r\n        package=&quot;%package%&quot;\r\n        android:versionCode=&quot;%versionCode%&quot;\r\n        android:versionName=&quot;%versionName%&quot;&gt;\r\n\r\n    &lt;!-- This is the platform API where NativeActivity was introduced. --&gt;\r\n    &lt;uses-sdk android:minSdkVersion=&quot;%minSdkVersion%&quot; \/&gt;\r\n&lt;%uses-permission%&gt;\r\n    &lt;application android:persistent=&quot;%persistent%&quot; \r\n        android:restoreAnyVersion=&quot;%restoreAnyVersion%&quot; \r\n        android:label=&quot;%label%&quot; \r\n        android:installLocation=&quot;%installLocation%&quot; \r\n        android:debuggable=&quot;%debuggable%&quot; \r\n        android:largeHeap=&quot;%largeHeap%&quot;\r\n        android:icon=&quot;%icon%&quot;\r\n        android:theme=&quot;%theme%&quot;&gt;\r\n        &lt;!-- Our activity is a subclass of the built-in NativeActivity framework class.\r\n             This will take care of integrating with our NDK code. --&gt;\r\n        &lt;activity android:name=&quot;com.embarcadero.firemonkey.FMXNativeActivity&quot;\r\n                android:label=&quot;%activityLabel%&quot;\r\n                android:configChanges=&quot;orientation|keyboardHidden&quot;&gt;\r\n            &lt;!-- Tell NativeActivity the name of our .so --&gt;\r\n            &lt;meta-data android:name=&quot;android.app.lib_name&quot;\r\n                android:value=&quot;%libNameValue%&quot; \/&gt;\r\n            &lt;meta-data android:name=&quot;android.hardware.usb.action.USB_DEVICE_ATTACHED&quot;\r\n                android:resource=&quot;@xml\/device_filter&quot; \/&gt;\r\n            &lt;intent-filter&gt;  \r\n                &lt;action android:name=&quot;android.intent.action.MAIN&quot; \/&gt;\r\n                &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; \/&gt;\r\n                &lt;action android:name=&quot;android.hardware.usb.action.USB_DEVICE_ATTACHED&quot; \/&gt;\r\n            &lt;\/intent-filter&gt; \r\n        &lt;\/activity&gt;\r\n        &lt;receiver android:name=&quot;com.embarcadero.firemonkey.notifications.FMXNotificationAlarm&quot; \/&gt;\r\n    &lt;\/application&gt;\r\n&lt;\/manifest&gt;   \r\n&lt;!-- END_INCLUDE(manifest) --&gt;\r\n<\/pre>\n<p>Ok. So now you should be able to deploy the application to the Android device and connect to the G2.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I first tried to use Libusb to connect my Android tablet with the G2. I managed to compile the libusb sources for Android and call it from the application, only to run into the &#8220;No permissions&#8221; error on trying to open the device. There is no easy solution for this at the moment, other than [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[],"_links":{"self":[{"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=\/wp\/v2\/posts\/65"}],"collection":[{"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=65"}],"version-history":[{"count":23,"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=\/wp\/v2\/posts\/65\/revisions"}],"predecessor-version":[{"id":83,"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=\/wp\/v2\/posts\/65\/revisions\/83"}],"wp:attachment":[{"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=65"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=65"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bverhue.nl\/g2dev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=65"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}