Category: Firemonkey

GetAccounts for Android (target 26) using Delphi 10.3 [on hold]

I'm using Delphi 10.3 for developing android application. I need to get the available account details in the mobile. I have provided the permission for GetAccounts and how can I get the available account details? Previously I have tried out the following code: function GetAccountEmails: TStringList; var jAm: JAccountManager; accounts: TJavaObjectArray<JAccount>; jAcc: JAccount; begin Result := TStringList.Create; jAM := TJAccountManager.JavaClass.get(SharedActivityContext); if jAM <> nil then begin accounts := TJavaObjectArray<JAccount>.Wrap(jAM.getAccountsByType(StringToJString('com.google'))); if accounts <> nil then begin //CommonFuncsProcs.DisplayThreadedMessage(IntToStr(accounts.Length)); //mmLog.Lines.Add('Length Accounts: ' + IntToStr(accounts.Length)); //SetLength(Result, accounts.Length); if accounts.Length > 0 then begin jAcc := accounts.Items[0]; //mmLog.Lines.Add(JStringtoString(jAcc._Getname)); Result.Add( JStringtoString(jAcc._Getname) ); end else begin //mmLog.Lines.Add('no accounts available'); end; end; end else begin //mmLog.Lines.Add('no accounts found'); end; end; But this code does not work for the Android targeting 26. Is there any code to implement Delphi 10.3 for targeting Android 26?
Read More

TMS FNC Cloud Pack is here!

First release!

We are excited to announce the first release of the TMS FNC Cloud Pack!

What’s included

Included in the TMS FNC Cloud Pack is the ability to create/implement your own REST service client(s). There is a small accompanying guide available after installation, that explains a few of the basics to get started. Additionally, below is a list of some of the many features that are supported in the TMS FNC Cloud Pack.

  • Create your own REST service client(s) built on top of the TMS FNC Cloud Pack core
  • One source code base to use on multiple frameworks (FMX, VCL, WEB and LCL)
  • Make GET, POST, PUT, UPDATE, DELETE and PATCH requests
  • Support for multi-part form data via a separate form data builder class
  • Built-in OAuth 2.0 authentication flow
  • Built-in URL encoding, JSON parsing, file to Base64 encoding and many more

Included in the TMS FNC Cloud Pack is a set of ready-to-use REST service client implementations that are listed below.

  • Google Tasks
  • Google Calendar
  • Google Contacts
  • Google Firebase Database
  • Google Drive
  • Google GMail
  • Google Search terms
  • Google Maps address data
  • Google Photos
  • Microsoft Onedrive
  • Outlook Calendar
  • Outlook Contacts
  • Outlook Mail
  • Apple CloudKit
  • DropBox Cloud storage
  • PayPal
  • YouTube
  • Hubic
  • myCloudData.net

<!–

  • Imgur

–>

How to create your own REST service client?

To illustrate how to create your own REST service client, we take the source code from accessing a Google service, such as Google Drive. Google Drive has a common layer in where the authentication flow and access token generation are handled to allow other services from Google implement the API’s on top of this layer.

The first step is to generate the authentication URL.

function TTMSFNCCustomCloudGoogle.GetAuthenticationURL: string;
begin
  Result := InitializeAuthenticationURL(Self);
end;

function InitializeAuthenticationURL(const ACloudBase: TTMSFNCCloudBase): string;
var
  url, sc: string;
begin
  sc := TTMSFNCCloudBaseOpen(ACloudBase).GetScopes('+', True);
  url :=
      '?scope=' + sc
    + '&state=profile'
    + '&redirect_uri='+ TTMSFNCUtils.URLEncode(ACloudBase.Authentication.CallBackURL)
    + '&response_type=code'
    + '&client_id=' + ACloudBase.Authentication.ClientID
    + '&approval_prompt=force'
    + '&access_type=offline'
    + '&hl=en';

  url := 'https://accounts.google.com/o/oauth2/auth' + url;

  Result := url;
end;

The URL is a concatenation of The ClientID, CallBackURL, some default parameters and a set of scopes, which is crucial to allow the user to identify which services is accessing which information. For Google Drive, the scopes are added in the constructor:

  Scopes.Clear;
  Scopes.Add('https://www.googleapis.com/auth/drive');
  Scopes.Add('https://www.googleapis.com/auth/drive.file');
  Scopes.Add('https://www.googleapis.com/auth/userinfo.profile');

When calling the Connect method, and the Access Token is not yet retrieved, or no longer valid, a browser is shown which allows identifying and authorizing the application which is requesting access to your files/folders and account information. Below is a screenshot of the browser and the scopes that are requested via the authorization URL.

After Clicking on the “Allow” button, the Application is redirected back to your application which runs an HTTP Server listening to the Callback URL & Port set via Authentication.CallBackURL. As soon as the HTTP Server catches the OAuth 2.0 redirect callback URL, it parses the URL and generates an authentication token. The next step is to take the authentication token and convert it to an access token:

procedure TTMSFNCCustomCloudGoogle.RetrieveAccessToken;
begin
  InitializeRetrieveAccessTokenRequest(Self);
  ExecuteRequest({$IFDEF LCLWEBLIB}@{$ENDIF}DoRetrieveAccessToken);
end;

procedure InitializeRetrieveAccessTokenRequest(const ACloudBase: TTMSFNCCloudBase);
begin
  ACloudBase.Request.Clear;
  ACloudBase.Request.Name := 'RETRIEVE ACCESS TOKEN';
  ACloudBase.Request.Host := 'https://accounts.google.com';
  ACloudBase.Request.Path := '/o/oauth2/token';
  ACloudBase.Request.Query :=  'client_id=' + ACloudBase.Authentication.ClientID
  + '&client_secret=' + ACloudBase.Authentication.Secret
  + '&redirect_uri=' + ACloudBase.Authentication.CallBackURL
  + '&code=' + ACloudBase.Authentication.AuthenticationToken
  + '&grant_type=authorization_code';
  ACloudBase.Request.Method := rmPOST;
end;

In the access token request, you’ll notice that the secret, authentication token, and callback URL are required to identify your application request and make sure the service returns the correct access token. The request is executed and automatically handled by the core layer in TMS FNC Cloud Pack. There is no need to manually parse the access token, unless the service deviates from the default OAuth 2.0 authentication flow.

After retrieving the access token, the service core layer is automatically performing a test to validate the access token and grant access to service API’s. The test needs to be handled by your service implementation. For Google Drive, the test involves calling a simple tokeninfo API endpoint to validate the tokens, but for other services, it could be retrieving the account information, or testing a retrieval of files/folders.

procedure TTMSFNCCustomCloudGoogle.TestTokens(const ATestTokensRequestResultEvent: TTMSFNCCloudBaseRequestResultEvent = nil);
begin
  InitializeTestTokensRequest(Self);
  ExecuteRequest(ATestTokensRequestResultEvent);
end;

procedure InitializeTestTokensRequest(const ACloudBase: TTMSFNCCloudBase);
begin
  ACloudBase.Request.Clear;
  ACloudBase.Request.Name := 'TEST TOKENS';
  ACloudBase.Request.Host := 'https://www.googleapis.com';
  ACloudBase.Request.Path := '/oauth2/v1/tokeninfo';
  ACloudBase.Request.Query := 'access_token=' + ACloudBase.Authentication.AccessToken;
  ACloudBase.Request.Method := rmGET;
end;

After executing the test tokens request, the service returns a JSON response which is unique for each service. For Google Drive, this is checking if the returned JSON does not have an error tag.

function TTMSFNCCustomCloudGoogle.GetTestTokensResult(
  const ARequestResult: TTMSFNCCloudBaseRequestResult): Boolean;
begin
  Result := InitializeTestTokensResult(Self, ARequestResult)
end;

function InitializeTestTokensResult(const ACloudBase: TTMSFNCCloudBase; const ARequestResult: TTMSFNCCloudBaseRequestResult): Boolean;
var
  o: TJSONValue;
  s: string;
begin
  Result := False;
  s := ARequestResult.ResultString;
  if s  '' then
  begin
    o := TTMSFNCUtils.ParseJSON(s);
    if Assigned(o) then
    begin
      Result := not Assigned(TTMSFNCUtils.GetJSONValue(o, 'error'));
      o.Free;
    end;
  end;
end;

The result is a Boolean (true/false). When the result is a true, the service is successfully authenticated, and the application can start accessing various API’s. Below is a sample that shows how to use the access token to retrieve the account drive space info.

procedure TTMSFNCCustomCloudGoogleDrive.GetAccountInfo;
begin
  Request.Clear;
  Request.Host := Service.BaseURL;
  Request.Path := FBasePath + '/about';
  Request.Query := 'access_token=' + Authentication.AccessToken;
  Request.Method := rmGET;
  Request.Name := 'GET SPACE USAGE';
  ExecuteRequest({$IFDEF LCLWEBLIB}@{$ENDIF}DoRequestGetSpaceUsage);
end;

procedure TTMSFNCCustomCloudGoogleDrive.DoRequestGetSpaceUsage(const ARequestResult: TTMSFNCCloudBaseRequestResult);
var
  o: TJSONValue;
begin
  if ARequestResult.ResultString  '' then
  begin
    o := TTMSFNCUtils.ParseJSON(ARequestResult.ResultString);

    if Assigned(o) then
    begin
      try
        FInfo.UserName := TTMSFNCUtils.GetJSONProp(o, 'displayName');
        FInfo.Quota := TTMSFNCUtils.GetJSONDoubleValue(o, 'quotaBytesTotal');
        FInfo.QuotaUsed := TTMSFNCUtils.GetJSONDoubleValue(o, 'quotaBytesUsed');

      finally
        o.Free;
      end;
    end;
  end;

  DoGetSpaceUsage(FInfo, ARequestResult);
  DoGetCurrentAccount(FInfo, ARequestResult);
end;

Demo

Included in the release is a demo that allows you to test out each service individually in one easy and intuïtive overview. Click on the service of your choice and fill in your Application Client-ID, Secret and the appropriate Callback URL registered to your application. click on Authenticate and start exploring. The demo is available for FMX, VCL, WEB and LCL.

We want your feedback!

In this blog post, we already asked you for which service(s) you wish to see an implementation. We already received a lot of feedback, and want to thank you for this. This allows us to continue development in future updates of TMS FNC Cloud Pack. For those that didn’t yet fill in the survey, please go to https://www.survio.com/survey/d/N4J9X1C8L4V7K1U7V

We want your feedback, so we can improve the TMS FNC Cloud Pack even more, so we want to ask you for a thorough testing on TMS FNC Cloud Pack and provide us with any feedback, comments, suggestions and issues you experience. This can be done via comments on this blog, or an email to support@tmssoftware.com

Read More

Read More

Splash Screen with message in FireMonkey

I want a splash screen with a tLabel on it. This tLabel will be used to show the progress of the initialization tasks for the application, such as: "Starting up databases", "Setting up forms", etc. I have tried the following code, in the project file: Application.Initialize; FormSplash := TFormSplash.Create( Application ); FormSplash.OpenSplash; FormSplash.ShowProgress; Application.Run; It shows the splash-screen properly. However, the tLabel that should show each text posted to it in sequence when the splash-screen appears, shows only the last text posted. This happens even if I put a Sleep command after each text posted. I tried to post the texts on the FormCreate, FormShow and FormActivate events with the same result. The application is for Windows 32.
Read More

The TMS WebGMaps v3.1 update includes map styles and SVG markers

We’re pleased to announce TMS WebGMaps v3.1 has been released today. TMS VCL WebGMaps is our component for VCL development that exposes a myriad of geographical functions for integration in Delphi or C++Builder Windows applications while TMS FMX WebGMaps offers the same functionality for cross-platform FireMonkey applications on Windows, Mac, iOS and Android.

In this new version we introduce the functionality to display the map in a custom style. You can use the pre-defined Night Mode style or any other custom style.

The code needed for this is just one line of code:

    WebGMaps1.MapOptions.MapStyle := mstNightMode; 

The code needed for this is just two lines of code:

  WebGMaps1.MapOptions.CustomStyle.Text := '[JSON Object]';
  WebGMaps1.MapOptions.MapStyle := mstCustom;

Use the Google Maps Platform Styling Wizard as a quick way to generate your own JSON styling object.

Another new feature are SVG Markers. This technique allows to display markers with a custom shape based on a SVG path. Several pre-defined shapes are available as well as the possibility to add your own custom SVG path.

Adding markers with a custom shape is very easy as this code snippet shows:

var
  m: TMarker;
begin
  m := WebGMaps1.Markers.Add(WebGMaps1.MapOptions.DefaultLatitude, WebGMaps1.MapOptions.DefaultLongitude);
  m.Shape := msStar;
  m.ShapeColor := clYellow;
  m.ShapeScale := 2;
  WebGMaps1.UpdateMapMarker(m);

  m := WebGMaps1.Markers.Add(WebGMaps1.MapOptions.DefaultLatitude + 0.1, WebGMaps1.MapOptions.DefaultLongitude - 0.1);
  m.Shape := msStar;
  m.ShapeColor := clYellow;
  WebGMaps1.UpdateMapMarker(m);

  m := WebGMaps1.Markers.Add(WebGMaps1.MapOptions.DefaultLatitude - 0.1, WebGMaps1.MapOptions.DefaultLongitude - 0.1);
  m.Shape := msFavorite;
  WebGMaps1.UpdateMapMarker(m);

  m := WebGMaps1.Markers.Add(WebGMaps1.MapOptions.DefaultLatitude + 0.1, WebGMaps1.MapOptions.DefaultLongitude + 0.1);
  m.Shape := msHome;
  m.ShapeColor := clSkyBlue;
  m.ShapeScale := 2;
  WebGMaps1.UpdateMapMarker(m);
end;

Today’s update also includes other smaller new features and improvements.
We look forward to learn about your interesting integrations of TMS WebGMaps in your applications!

Read More

Read More

Delphi FMX TIntegerColumn SetValue: Invalid Typecast

I have an FMX TGrid with a checkbox column, a string column and an integer column. I've managed to make the string column and checkbox columns work. But when I change the integer column, the TValue passed to the SetValue command does not seem to be passing an integer. I've set up a string column (StrNumber) to do what I want, but if I try to handle the value from the IntegerColumn I get a ClassCastException. I've tried the various number types as well Value.AsBoolean, Value.AsString, etc. but I always get Invalid Typecast. procedure MyApp.SuppGridSetValue(Sender: TObject; const ACol, ARow: Integer; const Value: TValue); begin if SuppGrid.Columns[ACol] = StrNumber then Caption := IntToStr(StrToIntDef(Value.AsString,1)); else if SuppGrid.Columns[ACol] = Number then Value.AsInteger; //see note end; NOTE: In the code above "Value.AsInteger" wouldn't get used even if it did work but this demonstrates clearly that the issue isn't some other call creating the ClassCastException. When debugging the inspection window doesn't offer much either. It does appear that the value is coming in as all 0s or nils, no matter what I try to set it as. (FData:(FTypeInfo:$4012BC; FValueData:TValueDataImpl($B7D78E8) as IValueData; FAsUByte:0; FAsUWord:0; FAsULong:0; FAsObject:nil; FAsClass:nil; FAsSByte:0; FAsSWord:0; FAsSLong:0; FAsSingle:0; FAsDouble:0; FAsExtended:0; FAsComp:0; FAsCurr:0; FAsUInt64:0; FAsSInt64:0; FAsMethod:(Code:nil; Data:nil); FAsPointer:nil)) That is, I've tried (in the GetValue) setting a direct simple value: Value := 42; Also using a From call: Value := TValue.From<Integer>(42); //doesn't work for an integer column In these cases the value "42" shows up in the right column, but the value passed to the SetValue routine does not seem to have either the original value of 42, or the user's data.
Read More

When the application is closed, the Android Local service was stopped

I'm using Delphi 10.3 for developing android application and I have implemented Service to retrieve the data from Server. The thread was running properly but it closes when the app is closed. I have used the following code to run the service: DMService.StartCommand(); begin AddLog; //Log SampleThread := TThread.Create; Result := TJService.JavaClass.START_REDELIVER_INTENT; end; The same code worked fine in Delphi 10.1 (without mentioning the Android 26 as target version). Also I have tried using TTask but still the problem does not resolves. Also I have tried Result := TJService.JavaClass.START_STICKY;, but still the service closes. And after several analysis, I have analyzed after closing the host application the service, the Service starts again and the thread/Task initiated and the service was destroyed. Should I need to enable any special permission or while creating should I need to add more code. Currently, I'm using the following code for initiating the service from the host application: FLocalServiceConnection := TLocalServiceConnection.Create; FLocalServiceConnection.StartService('SCommuteSupervisorNotificationService'); Please help me to resolve this issue to run the service after the host app closes.
Read More

TChart not visible on Android

I'm using RAD Studio 10.2 With TeeChart components. I've made a simple TChart component with code shown below. Everything works fine when I compile and run my program on Windows, but when I try to run Android version, TChart component is not visible. No error, nothing, just not showing up. I've tried looking for answer (as I persume, there is some specific thing I should do to make the TChart show up on android) but I just can't find any relevant question. Thank you in advance for your help. Chart1.LeftAxis.Title.Caption:='A1 [-] , A2 [-]'; Chart1.BottomAxis.Title.Caption:='t [s]'; Series1.Title:='A1'; Series2.Title:='A2'; Chart1.Legend.Visible:=True; Chart1.Series[0].Clear; Chart1.Series[1].Clear; for i := 1 to num do Chart1.Series[0].AddXY(Tablica[0][i],Tablica[6][i]); for i := 1 to num do Chart1.Series[1].AddXY(Tablica[0][i],Tablica[7][i]);
Read More

Problem displaying hints in FMX Win32 application

I have an application where menu buttons are enabled or disabled depending on the active tab in a tab control. When the tab switches, the appropriate button(s) are enabled but when you first hover over a menu button the hint does not appear. However, after moving off the button and then back over it, the hint appears. The expected use of this form is to switch tabs and then selected a menu button, so this behavior will be very confusing to the user. This does not happen with the VCL but with FMX on Win32. I have tried several different workarounds (resetting the ShowHint property, trying to do something on OnMouseEnter). Currently running Delphi Rio on a Windows 10 PC. procedure TForm1.CheckBox1Change(Sender: TObject); begin Button1.Enabled := CheckBox1.IsChecked; end; procedure TForm1.FormCreate(Sender: TObject); begin Button1.Hint := 'Hint for button1'; Button1.ShowHint := true; end; Start a new application and drop a TButton and TCheckbox onto the form. Set the checkbox's onchange event. Run the program, hover to see the hint then click the checkbox to disabled and then enabled the button. Then hover over the button to see the effect - the hint will not appear on the first hover, only on subsequent hovers. Any idea of a workaround aside from developing my own hint code? Thanks, Pat
Read More

What is Application icon size (83.5×83.5) for iOS?

In my Delphi Rio iOS project, when I go to Project options > Icons > Ipad I can see Application icon (83.5x83.5) but what does it mean 83.5x83.5? It's not possible to make an image of 83.5x83.5 pixels, so what is the desired pixel size? When I look the dimension of C:\Program Files (x86)\Embarcadero\Studio\20.0\bin\Artwork\iOS\iPad\FM_ApplicationIcon_83.5x83.5.png It is 83 x 83 pixels, not 83.5 x 83.5 Is there something wrong?
Read More

What’s wrong with my implementation regarding light status bar flag?

I was looking for a solution on a darker status bar foreground on a light (white) status bar background. I am using Delphi 10.3 (Rio) and an Android version 8.1.0 device. My code supposedly works based on Android samples I have looked. I have tried several Android references pertaining to the status bar. The following is my code that didn't work. I don't know what's missing. setStatusBarColor is working setSystemUiVisibility is not. procedure TfrmMain.FormCreate(Sender: TObject); var lbl: TLabel; uiOptions: Integer; begin CallInUIThread( procedure begin SharedActivity.getWindow.clearFlags(TJWindowManager_LayoutParams.JavaClass.FLAG_TRANSLUCENT_STATUS); SharedActivity.getWindow.addFlags(TJWindowManager_LayoutParams.JavaClass.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); SharedActivity.getWindow.setFlags(TJWindowManager_LayoutParams.JavaClass.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, TJWindowManager_LayoutParams.JavaClass.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); uiOptions := SharedActivity.getWindow.getDecorView.getSystemUiVisibility(); SharedActivity.getWindow.getDecorView.setSystemUiVisibility(TJview.JavaClass.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); SharedActivity.getWindow.setStatusBarColor(TJcolor.JavaClass.BLACK); end); end;
Read More

ld: framework not found Bolts for architecture armv7

I try to compile in Delphi Rio a project that was working fine under Delphi tokyo. I can't because I always have this error : ld: framework not found Bolts for architecture armv7 But in the global delphi library path I have correctly set: C:\lib\ios\facebook\Bolts.framework that is the path where is located the Bolts framework: C:\lib\ios\facebook\Bolts.framework\Headers\... C:\lib\ios\facebook\Bolts.framework\Modules\... C:\lib\ios\facebook\Bolts.framework\Info.plist C:\lib\ios\facebook\Bolts.framework\Bolts What did I miss ? Note: If I move the C:\lib\ios\facebook\Bolts.framework\ dir inside the global PlateformSDKs dir then it works.
Read More

IdHTTP to ensure push data to Ubidots (FMX, WIN32)

I can push an encrypted piece of humidity data up to my Ubidots cloud database by simply loading the following url in a web browser: https://industrial.ubidots.com/api/v1.6/devices/MYDEVICENAME/?token=MYTOKENHERE&_method=post&humidity=15.9 When I do that, I get the success response in the browser window {"humidity": [{"status_code": 201}]} and the data shows up in my data table on Ubidots. Now, I want to do this from an FMX app (C++ on Win32) without a visible browser, and I would like to check that I get the nice "201" response code. I looked at this link and cobbled up the following line of code: Memo1->Text = IdHTTP1->Get("https://industrial.ubidots.com/api/v1.6/devices/MYDEVICENAME/?token=MYTOKENHERE&_method=post&humidity=6.9"); When I run it, I get a "Could not load SSL library" error message. How do I tell TIdHTTP to use SSL so it can handle the HTTPS? Is there a better, cleaner way to do this?
Read More