Category: Firemonkey

How to alter the sensitivity of a FMX.TStringGrid to better respond to "click" rather than "scroll"

We have a Delphi 10.3 Rio FireMonkey app. Part of the main form is a TStringGrid containing a list of materials. The user can touch "click" into a quantity cell to enter the amount of material they wish to use, or they can touch "scroll" the list up and down if there is more than the visible number of lines. The problem we have heard from our Android tablet users, is that it seems very unresponsive when trying to enter the quantity. They have to press several times into the cell before it goes into edit mode and allows them to enter a value. iPad and Windows users are not reporting this problem. We've tried several different Android devices, and they all exhibit the same issue. From discussions among ourselves, we've hit on the idea that the component is responding to the touch as the beginning of a scroll rather than the click of the cell, and we are wondering if there is a way to alter how the component behaves, or add events to either the TStringGrid or the TFloatColumn that would better detect the click and force it to edit the cell based on the hit test?
Read More

TScrollBox or TChart memory leak (FMX, C++)

I've been trying to find a memory leak on iOS and i'm 99% it is either in a TScrollBox or in a TChart. The action that leads to the crash is simple scrolling back and forth across the TChart. The app behaves well in Win32 and memory useage is stable. The crash cause on iOS is EXC_RESOURCE -> myappname[5548] exceeded mem limit: ActiveHard 1400MB (fatal) per Xcode Console. To exclude my spaghetti code as the culprit i created a simple project to reproduce the error and it crashes too. Below are snips from the Xcode Console output. I get tons of assertions, then the Received memory warning, then the iOS kernal kills my app (Project1). default 20:28:26.180333 -0500 assertiond [Project1:7693] Activate assertion: <BKProcessAssertion: 0x12b0102c0; "com.apple.UIKit.KeyboardManagement.message" (finishTask:180s); id:…8EA7F5E94DD5> default 20:28:26.180542 -0500 assertiond [Project1:7693] Setting jetsam priority to 10 [0x10108] default 20:28:26.182151 -0500 assertiond [Project1:7693] Deactivate assertion: <BKProcessAssertion: 0x12b0102c0; "com.apple.UIKit.KeyboardManagement.message" (finishTask:180s); id:…8EA7F5E94DD5> default 20:28:26.182312 -0500 assertiond [Project1:7693] Setting jetsam priority to 10 [0x10100] default 20:28:26.183307 -0500 assertiond [Project1:7693] Remove assertion: <BKProcessAssertion: 0x12b0102c0; "com.apple.UIKit.KeyboardManagement.message" (finishTask:180s); id:…8EA7F5E94DD5> default 20:28:32.609723 -0500 Project1 Received memory warning. Then a short time later i see the following console message: default 20:28:45.881914 -0500 kernel EXC_RESOURCE -> Project1[7693] exceeded mem limit: ActiveHard 1400 MB (fatal). My crash test app is a simple Firemonkey app built in C++ Builder 10.3.2. A) Put a TPanel on the form (Panel1). B) Put a TScrollBox on Panel1 (ScrollBox1). Set its align to Contents. C) Put a TLayout on ScrollBox1 (Layout1). Set its align to None. Set its width to 2100. D) Put a TChart on Layout1. Set its height to 200, width 7300. Set its align to None. E) Add a TToolBar to Form1 and put a TButton on it. F) Then put this code in the TButton's click event: Form1->Layout1->Position->X = 0; Form1->ChartTest->Position->Y = 0; Form1->ChartTest->Position->X = 0; TLineSeries *series1 = new TLineSeries(Form1); TLineSeries *series2 = new TLineSeries(Form1); TLineSeries *series3 = new TLineSeries(Form1); TLineSeries *series4 = new TLineSeries(Form1); series1->Color = claBlue; series2->Color = claRed; series3->Color = claBlueviolet; series4->Color = claAqua; double x, y; for (int i = 0; i < 1000; i++) { x = i; y = Random(5000); series1->AddXY(x,y); y = Random(5000); series2->AddXY(x,y); y = Random(5000); series3->AddXY(x,y); y = Random(5000); series4->AddXY(x,y); } Form1->ChartTest->AddSeries(series1); Form1->ChartTest->AddSeries(series2); Form1->ChartTest->AddSeries(series3); Form1->ChartTest->AddSeries(series4); G) And now, with your iOS device connected to your mac and Xcode Console open, filter the Console output on "Project1" if that is what you named it. Then run the app and scroll backwards/forwards and/or up/down (also change orientation if you want back and forth). You will see tons of assertions. Eventually (takes around 2-3 minutes of this harassment to make it crash) it will eat up enough memory that it crashes. I think the memory leak is in the TeeChart most likely, maybe in the TScrollBox? thanks, russ
Read More

After redeploying a FireMonkey app to my physical device, GetDocumentsPath always contains older asset files

I'm developing a Delphi FireMonkey app and I'm testing it using some assets. It seems to work fine. However, now I completely removed all assets from the Deployment Manager and whenever I remove the app from my device (using some ADB shell commands, I can verify that the app directory is completely removed) and run the app again in debug from the IDE, some older assets appear again. (in fact, 1 SQLite database file and a tmp file representing the form savestate. They have normal file attributes, but the file dates are 1970-01-19). Using the ADB shell command again, I notice these files reappear BEFORE the app hits the StartupCopy unit initialization! I've verified many things, but I have no idea where they keep re-appearing from (from Android itself or transferred from my PC, but since I removed them all, this is very unlikely). I'm very puzzled with this. If I delete only the data files from the app on the device, this does not happen. Only when I completely remove the app. Is there a backup/init/loading mechanism on Android itself that might cause this? Since my device is not rooted, looking on the device itself is limited. ls -l of my app's directory: -rw------- 1 u0_a289 u0_a289 4 1970-01-19 03:56 FM_TMainForm_MainForm.TMP -rw------- 1 u0_a289 u0_a289 217088 1970-01-19 03:45 dancegenie.sqlite
Read More

TDirectory::GetFiles listing ignoring case on iOS (FMX, C++)

The code below lists files that have extension .cfg and it works fine on Win32. But, on iOS if i have a file that a user named with caps for the extension (e.g. test.CFG) then i miss it. I found this post using Delphi that might work using TDirectory::TFilterPredicate but i don't know how to implement in C++Builder. TStringDynArray list; TSearchOption searchOption; UnicodeString DocsPath; int lenDocsFolder; DocsPath = System::Ioutils::TPath::GetDocumentsPath(); lenDocsFolder = DocsPath.Length(); searchOption = TSearchOption::soTopDirectoryOnly; try { list = TDirectory::GetFiles(DocsPath, "*.cfg", searchOption); } catch (...) { ShowMessage("Incorrect path or search mask"); return; } I suppose i can just run a *.cfg block of code followed by a *.CFG but i'm hoping there is a cleaner approach.
Read More

Change folder attribute to hidden on iOS (FMX, C++)

I want to create a directory at runtime and make it hidden. Using this example i tried the following code and it works fine on Win32 but errors on iOS build: UnicodeString TestPath; TestPath = System::Ioutils::TPath::GetDocumentsPath() + "\\test\\"; TDirectory::CreateDirectory(TestPath); TFileAttributes dirattribs; dirattribs = TDirectory::GetAttributes(TestPath); dirattribs = dirattribs << TFileAttribute::faHidden; TDirectory::SetAttributes(TestPath, dirattribs); The build error i get when building for iOS or Android is no member named 'faHidden' in 'System::Ioutils::TFileAttribute'. So, how can i change folder attributes on iOS and Android? p.s. Using Rad Studio 10.3.2 (C++ Builder).
Read More

Printing Bitmap Using Bluetooth Thermal Printer With Firemonkey Android

I have this code is success for printing text with bluetooth thermal printer using android using firemonkey delphi, my friend modified for printing bitmap, but any some error access violation with procedure bitmaptostr. procedure TBluetoothPrinter.Send(Data: TArray<Byte>); begin if Data = nil then Exit; // nothing to write Check(OutputStream <> nil, 'Cannot retrieve output stream'); OutputStream.write(ToJavaByteArray(Data)); end; procedure Printing(sText: string); begin with TBluetoothPrinter.Create do begin Send(TEncoding.ANSI.GetBytes(sText + CRLF)); end; end; function BitmapToStr(BMP: TBitmap; EscapeStr:String; SliceEscapeStr:String; BitsSlice: Byte = 8):String; var BMPData: TBitmapData; AColor: TAlphaColor; nCol, nRow, nIndex: integer; nOffset, nBytePos, nBitPos: integer; nSliceIndex, nLum: integer; nSlice, nBit, nTmpBit, BytesSlice: byte; ADots: Array of boolean; sSlice: String; begin try SetLength(ADots, (BMP.Height * BMP.Width)); nIndex := 0; for nRow := 0 to BMP.Height-1 do begin for nCol := 0 to BMP.Width-1 do begin AColor := BMPData.GetPixel(nCol, nRow); nLum := Trunc((TAlphaColorRec(AColor).R * 0.3) + (TAlphaColorRec(AColor).G * 0.59) + (TAlphaColorRec(AColor).B * 0.11)); ADots[nIndex] := (nLum < 127); inc(nIndex); end; end; BytesSlice := (BitsSlice div 8); if BitsSlice mod 8 > 0 then inc(BytesSlice); Result := EscapeStr; nOffset := 0; while (nOffset < BMP.Height) do begin Result := Result + SliceEscapeStr; for nCol := 0 to BMP.Width-1 do begin for nSliceIndex := 0 to BytesSlice - 1 do begin nSlice := 0; for nBit := 0 to 7 do begin nBytePos := (((nOffset div 8) + nSliceIndex) * 8) + nBit; nBitPos := (nBytePos * BMP.Width) + nCol; nTmpBit := 0; if (nBitPos < Length(ADots)) then begin if ADots[nBitPos] then nTmpBit := 1 else nTmpBit := 0; end; nSlice := nSlice or (nTmpBit shl (7 - nBit)); end; Result := Result + Chr(nSlice); end; end; inc(nOffset, BitsSlice); Result := Result + CRLF; end; finally ADots := nil; end; end; anyone have some solution or sample reference?
Read More

How to add and remove Android notification channels in Delphi Rio10.3.2

I would like to implement multiple notification channels for Android on an FMX project. RAD 10.3.2 now provides some support for API >= 26 and a "fallback" notification channel is automatically created. Its default description is "Notification channel for Firebase" and I would like to change this description as well as to add some new channels. In RAD 10.3.2, the new Options/Application/Services parameters provide a "Default local notification channel Id" which, I suppose, is there to change the value of the fcm_fallback_notification_channel_label stored in the Strings.xml file generated when building or deploying the App. However, when I write an Id like "Infos" in this field, this has no effect on the generated Strings.xml file content. I've thus copied the Strings.xml file in another directory, edited it manually and modified the deployment in order to use this file rather than the automatic one. This is working if I uninstall the App and reinstall it with the changed channel description. The final user may now see the correct name of the channel. However, I've still got only one channel and I don't know how to add more ones. I've searched in the Android support and I see that the channels are supposed to be added via notificationManager.createNotificationChannel(channel) in the starting code of an App. However, I've found no access to these method in TPushService or TPushServiceConnection. Is there a "standard" way in Delphi for adding and removing notification channels ?
Read More