1

I want to code a motion detector (Accelerometer) using the AndroidApi directly. I currently have tested implementations (per Embarcadero examples) using TMotionSensor as well as TSensorManager, but both seem to have power drain issues (ie. the phone gets hot).

My TSensorManager implementation looks like this:

procedure TfrmTabbed.InitSensorMan;
var
  FSensors: TSensorArray;
  Sensor: TCustomSensor;
begin
  TSensorManager.Current.Activate;
  FSensors := TSensorManager.Current.GetSensorsByCategory(TSensorCategory.Motion);
  FSensor := nil;
  for Sensor in FSensors do
  begin
    if TCustomMotionSensor(Sensor).SensorType = TMotionSensorType.Accelerometer3D then
    begin
      FSensor := TCustomMotionSensor(Sensor);
      Break;
    end;
  end;
  MotionTimer.Interval := 250; 
  MotionTimer.Active := True;
end;

So now, using How to detect movement of an android device? as a reference, I start writing code like this:

uses
  Androidapi.Sensor,
  Androidapi.JNI.JavaTypes;

{$R *.fmx}

procedure TForm2.FormCreate(Sender: TObject);
var
  Obj: JObject;
  SensorManager: JSensorManager;
begin

  Obj := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.SENSOR_SERVICE);
  if Obj <> nil then
  begin
     SensorManager := TJsensorManager.Wrap(Obj);

  end;

I guess anyone who is familiar with this area, will realize that there's no JSensorManager declared anywhere in C:\Program Files (x86)\Embarcadero\Studio\18.0\source. There's a Androidapi.JNI.Telephony.pas, but no Androidapi.JNI.Sensor(s).pas!

My question is, is it possible to access the SENSOR_SERVICE from Delphi in this way, and if so, how can I implement it?

Addendum

I tried Java2op. It seems to require a very specific version (1.7.25?) of the JDK to not produce a "class or interface expected" error. So I tried Java2Pas instead. The free version only parses Android.jar, but that seems to be sufficient for my purposes.

Freddie Bell
  • 2,186
  • 24
  • 43
  • 1
    You'll need to become familiar with the Java2OP tool (as well as its limitations) that can be used to import SensorManager. You'll also need know how to create a class that implements (once you've imported the SensorManager) JSensorEventListener. I suggest watching Brian Long's video here: https://www.youtube.com/watch?v=GcuYc7F0lIU – Dave Nottage Sep 08 '17 at 21:19
  • @Dave Nottage. Thanks I appreciate the response. – Freddie Bell Sep 09 '17 at 11:49

1 Answers1

2

Here is my (almost completed) answer for those of you who are trying to do the same (or similar) things, especially with Listeners, in Delphi Android 10.x.

Note:

  1. SensorListener has been deprecated in Android. Use SensorEventListener instead.

  2. Java2pas coded the JSensorEventListener in android.hardware.SensorEventListener.pas incorrectly. It was JSensorEventListener = interface(JObject). It must be corrected to JSensorEventListener = interface(IJavaInstance).

  3. In android.hardware.SensorEvent, the values property and the _Getvalues function, was missing from the JSensorEvent declaration. Just copy them from the JSensorEventClass.

Here is the code:

unit Unit2;

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.StdCtrls
 , Androidapi.JNIBridge
 , Androidapi.JNI.Embarcadero
 , Androidapi.JNI.GraphicsContentViewText
 , androidapi.JNI.JavaTypes
 , AndroidApi.JNI.Location
 , Androidapi.JNI.Os
 // java2pas gen'd units (modified as noted above)
 , android.hardware.SensorManager
 , android.hardware.Sensor
 , android.hardware.SensorEventListener
 , android.hardware.SensorEvent
 , FMX.ScrollBox, FMX.Memo
 ;

type

  TSensorEventListener = class;

  TForm2 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FSensorManager: JSensorManager;
    FDefaultSensor: JSensor;
    SensorEventListener: TSensorEventListener;
    FStarted: Boolean;
    procedure StartApi;
    procedure StopApi;
  public
    { Public declarations }
  end;

  TSensorEventListener = class(TJavaLocal, JSensorEventListener)
  private
    [weak]
    FParent: TForm2;
  public
    constructor Create(AParent: TForm2);
    procedure onAccuracyChanged(JSensorparam0 : JSensor; Integerparam1 : Integer) ; cdecl;
    procedure onSensorChanged(JSensorEventparam0 : JSensorEvent) ; cdecl;
  end;

var
  Form2: TForm2;

implementation

uses
  Androidapi.Helpers
  , Androidapi.JNI.Net
  , FMX.Helpers.Android
  ;

procedure TForm2.Button1Click(Sender: TObject);
begin
  if Fstarted then
    StopApi
  else
    StartApi;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  FStarted := False;
end;

procedure TForm2.StartApi;
var
  SensorManagerService: JObject;
begin
  if not Assigned(FSensorManager) then
  begin
    SensorManagerService := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.SENSOR_SERVICE);
    FSensorManager := TJSensorManager.Wrap((SensorManagerService as ILocalObject).GetObjectID);
    if not Assigned(SensorEventListener) then
      SensorEventListener := TSensorEventListener.Create(Self);
    FDefaultSensor := FSensorManager.getDefaultSensor(TJSensorManager.JavaClass.SENSOR_ACCELEROMETER);
  end;
  FSensorManager.registerListener(SensorEventListener, FDefaultSensor, TJSensorManager.JavaClass.SENSOR_DELAY_NORMAL);
  Memo1.Lines.Add(DateTimeToStr(Now) + ' started');
  FStarted := True;
end;

procedure TForm2.StopApi;
begin
  if Assigned(SensorEventListener) then
    FSensorManager.unregisterListener(SensorEventListener);
  Memo1.Lines.Add(DateTimeToStr(Now) + ' stopped');
  FStarted := False;
end;

{ TSensorEventListener }

constructor TSensorEventListener.Create(AParent: TForm2);
begin
  inherited Create;
  FParent := AParent;
end;

procedure TSensorEventListener.onAccuracyChanged(JSensorparam0: JSensor;
  Integerparam1: Integer);
begin
   // do stuff
end;

procedure TSensorEventListener.onSensorChanged(
  JSensorEventparam0: JSensorEvent);
begin
   // do stuff, especially with the JSensorEventparam0.values
end;
Freddie Bell
  • 2,186
  • 24
  • 43