Warm tip: This article is reproduced from serverfault.com, please click

Delphi GPS Sensor doesn't show coordinates

发布于 2020-12-02 11:27:49

I have a fmx form with nothing more than a LocationSensor, a Memo and a Button on it and used the code below to display the coordinates in a memo. When I have GPS turned on on my phone "1" and "2" are shown when I click the button, so that seems to work, but there are no lines in my Memo added. I tried different code examples but not a single one worked for me to display coordinates in any way.

I use a Samsung A3 (SM-A310F) with at first stock rom (Android 7) and now with Lineage 17.1 (based on Android 10) to test it and on both versions nothing with GPS Coordinates worked so far. I use Delphi 10.3.3 Community Edition.

What am I doing wrong?

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.ScrollBox,
  FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls, System.Sensors,
  System.Sensors.Components,

  Androidapi.JNI.Location,
  Androidapi.JNIBridge,
  FMX.Helpers.Android,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.Helpers;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    LocationSensor1: TLocationSensor;
    procedure Button1Click(Sender: TObject);
    procedure LocationSensor1LocationChanged(Sender: TObject;
      const OldLocation, NewLocation: TLocationCoord2D);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
var
  locationManager: JLocationManager;
begin

  LocationSensor1.Active := true;

  locationManager := TJLocationManager.Wrap
    (((SharedActivity.getSystemService(TJContext.JavaClass.LOCATION_SERVICE))
    as ILocalObject).GetObjectID);

  if locationManager.isProviderEnabled(TJLocationManager.JavaClass.GPS_PROVIDER)
  then
  begin
    showmessage('1');
  end;

  if locationManager.isProviderEnabled
    (TJLocationManager.JavaClass.NETWORK_PROVIDER) then
  begin
    showmessage('2');
  end;
end;

procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;
  const OldLocation, NewLocation: TLocationCoord2D);
begin
  Memo1.Lines.Add(FloatToStr(NewLocation.Longitude));
  Memo1.Lines.Add(FloatToStr(NewLocation.Latitude));
end;

end.

Update: I found a spanish solution (see below)

Questioner
qGold
Viewed
0
qGold 2020-12-02 21:13:16

I found a solution on YouTube in spanish: https://www.youtube.com/watch?v=iiPFpzGICws which links me to this file: https://drive.google.com/file/d/1kGHlaaSfSfeAcOsiWG7mAsH5Vl_kXdzS/view

I dont know any Spanish, but I try to understand, what he does and I will reuse his version for my app now. It is the only version on the Internet I found so far and it works awesome.

So in case the links get deleted here is the code provided:

unit Form_Principal;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
  FMX.WebBrowser, FMX.StdCtrls, FMX.Controls.Presentation, FMX.Objects,
  System.Permissions, System.Sensors, System.Sensors.Components;

type
  TForm1 = class(TForm)
    WebBrowser: TWebBrowser;
    Layout1: TLayout;
    Switch: TSwitch;
    Label1: TLabel;
    Layout2: TLayout;
    RoundRect1: TRoundRect;
    lbl_endereco: TLabel;
    LocationSensor: TLocationSensor;
    procedure FormCreate(Sender: TObject);
    procedure SwitchClick(Sender: TObject);
    procedure LocationSensorLocationChanged(Sender: TObject; const OldLocation,
      NewLocation: TLocationCoord2D);
    procedure lbl_enderecoClick(Sender: TObject);
  private
    { Private declarations }
    Location: TLocationCoord2D;
    FGeocoder: TGeocoder;

    {$IFDEF ANDROID}
     Access_Fine_Location, Access_Coarse_Location : string;
     procedure DisplayRationale(Sender: TObject;
              const APermissions: TArray<string>; const APostRationaleProc: TProc);
     procedure LocationPermissionRequestResult
                (Sender: TObject; const APermissions: TArray<string>;
                const AGrantResults: TArray<TPermissionStatus>);
    {$ENDIF}

    procedure OnGeocodeReverseEvent(const Address: TCivicAddress);

  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses FMX.DialogService

{$IFDEF ANDROID}
,Androidapi.Helpers, Androidapi.JNI.JavaTypes, Androidapi.JNI.Os
{$ENDIF}

;

{$IFDEF ANDROID}

procedure TForm1.DisplayRationale(Sender: TObject;
  const APermissions: TArray<string>; const APostRationaleProc: TProc);
var
  I: Integer;
  RationaleMsg: string;
begin
  for I := 0 to High(APermissions) do
  begin
    if (APermissions[I] = Access_Coarse_Location) or (APermissions[I] = Access_Fine_Location) then
      RationaleMsg := 'O app precisa de acesso ao GPS para obter sua localização'
  end;

  TDialogService.ShowMessage(RationaleMsg,
    procedure(const AResult: TModalResult)
    begin
      APostRationaleProc;
    end)
end;

procedure TForm1.LocationPermissionRequestResult
  (Sender: TObject; const APermissions: TArray<string>;
const AGrantResults: TArray<TPermissionStatus>);
var
         x : integer;
begin
  if (Length(AGrantResults) = 2) and
    (AGrantResults[0] = TPermissionStatus.Granted) and
    (AGrantResults[1] = TPermissionStatus.Granted) then
    Form1.LocationSensor.Active := true
  else
  begin
    Switch.IsChecked := false;
    TDialogService.ShowMessage
      ('Não é possível acessar o GPS porque o app não possui acesso')
  end;

end;

{$ENDIF}

procedure TForm1.OnGeocodeReverseEvent(const Address: TCivicAddress);
var
        msg : string;
begin
        msg :=  Address.AdminArea + ', ' +
                Address.CountryCode + ', ' +
                Address.CountryName + ', ' +
                Address.FeatureName + ', ' +
                Address.Locality + ', ' +
                Address.PostalCode + ', ' +
                Address.SubAdminArea + ', ' +
                Address.SubLocality + ', ' +
                Address.SubThoroughfare + ', ' +
                Address.Thoroughfare;

        TDialogService.ShowMessage(msg);
end;

procedure TForm1.LocationSensorLocationChanged(Sender: TObject;
  const OldLocation, NewLocation: TLocationCoord2D);
var
        lt, lg, url : string;
begin
        Location := NewLocation;
        lt := StringReplace(Format('%2.6f', [NewLocation.Latitude]), ',', '.', [rfReplaceAll]);
        lg := StringReplace(Format('%2.6f', [NewLocation.Longitude]), ',', '.', [rfReplaceAll]);

        LocationSensor.Active := false;
        Switch.IsChecked := false;

        url := 'https://maps.google.com/maps?q=' + lt + ',' + lg;
        WebBrowser.Navigate(url);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
        {$IFDEF ANDROID}
        Access_Coarse_Location := JStringToString(TJManifest_permission.JavaClass.ACCESS_COARSE_LOCATION);
        Access_Fine_Location := JStringToString(TJManifest_permission.JavaClass.ACCESS_FINE_LOCATION);
        {$ENDIF}
end;



procedure TForm1.lbl_enderecoClick(Sender: TObject);
begin
        try
                // Tratando a instancia TGeocoder...
                if not Assigned(FGeocoder) then
                begin
                        if Assigned(TGeocoder.Current) then
                                FGeocoder := TGeocoder.Current.Create;

                        if Assigned(FGeocoder) then
                                FGeocoder.OnGeocodeReverse := OnGeocodeReverseEvent;
                end;

                // Tratar a traducao do endereco...
                if Assigned(FGeocoder) and not FGeocoder.Geocoding then
                        FGeocoder.GeocodeReverse(Location);
        except
                showmessage('Erro no serviço Geocoder');
        end;
end;

procedure TForm1.SwitchClick(Sender: TObject);
begin
        if Switch.IsChecked then
        begin
                {$IFDEF ANDROID}
                PermissionsService.RequestPermissions([Access_Coarse_Location,
                                                       Access_Fine_Location],
                                                       LocationPermissionRequestResult,
                                                       DisplayRationale);
                {$ENDIF}

                {$IFDEF IOS}
                LocationSensor.Active := true;
                {$ENDIF}
        end;
end;




end.