-
Content Count
1424 -
Joined
-
Last visited
-
Days Won
32
Everything posted by Dave Nottage
-
Using iOS LocalNotification with EKAlarm, EKEvent, EKEventStore as "short time, timer alarm"
Dave Nottage replied to Rollo62's topic in Cross-platform
What are the actual requirements for the short-time timer? Is it to display a notification? How short is the "short-time"? Any other requirements?- 4 replies
-
- ios
- notification
-
(and 1 more)
Tagged with:
-
[Android] Retrieving photos from the camera roll that have been taken in a Delphi app
Dave Nottage posted a topic in Cross-platform
I'm having an issue with being able to retrieve photos from the camera roll when using TTakePhotoFromCameraAction. It's probably not a bug; it's more likely a case of "yet to be implemented" 🙂 I've attached a project that demonstrates the issue. On startup the test app requests permission to read external storage, then if granted proceeds to retrieve the photos from the camera roll. This works fine. When the TakePhoto button is clicked, the app requests permissions for the camera and to write to external storage, then proceeds to execute the action. When the user has finished taking the photo, the TakePhotoFromCameraActionDidFinishTaking event fires, and the app reloads the photos from the camera roll. One would expect the newly taken photo to be in the roll, however it is not. Restarting the app still does not show the new photo. Running the Photos app on the device shows the new photo, however with a slight delay before it actually appears - I'm not sure if this is a clue. Restart the test app again, et voila! The new photo is there. The question is: why does the photo not appear when restarting the app (not that I'd expect anyone to do this), and not until the Photos app has been run? AndroidGetPhoto.zip -
[Android] Retrieving photos from the camera roll that have been taken in a Delphi app
Dave Nottage replied to Dave Nottage's topic in Cross-platform
After a lot of Googling and experimenting, I managed to solve this myself. From what I could gather, and this may apply only to later versions of Android (I have Android 10 on my Pixel 3a), the method that FMX uses to "scan" the image file into the gallery, which is via an intent (source\rtl\androiddex\java\fmx\src\com\embarcadero\firemonkey\medialibrary\MediaImage.java): /** * Adds photo to Gallery application. */ public void addPhotoToGallery() { Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(getFileUri()); activity.sendBroadcast(intent); } Does not immediately update the media "database". I discovered that using the scanFile method of the MediaScannerConnection class: https://developer.android.com/reference/android/media/MediaScannerConnection Does cause an immediate update, so that requerying using ContentResolver now works. I used the code in this article: https://www.grokkingandroid.com/adding-files-to-androids-media-library-using-the-mediascanner/ To come up with the additional Delphi code required, which is in the attached test app. I've added some comments which should clarify the whys and hows. AndroidGetPhotoV2.zip -
iOSapi_AVFoundation AVAudioSession extension doesn't work
Dave Nottage replied to Rollo62's topic in Cross-platform
I should have realised from the beginning - it's a method resolution problem. The Objective-C method name is actually setCategory, not setCategoryWithOptionsError, so it needs a MethodName attribute. This executes without error for me: uses Macapi.ObjectiveC, Macapi.Helpers, iOSapi.Foundation, iOSapi.AVFoundation, iOSapi.CocoaTypes; const AVAudioSessionCategoryOptionNone = 0; AVAudioSessionCategoryOptionMixWithOthers = 1; AVAudioSessionCategoryOptionDuckOthers = 2; AVAudioSessionCategoryOptionAllowBluetooth = 4; AVAudioSessionCategoryOptionDefaultToSpeaker = 8; AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers = 17; AVAudioSessionCategoryOptionAllowBluetoothA2DP = 32; AVAudioSessionCategoryOptionAllowAirPlay = 64; type AVAudioSessionCategory = NSString; AVAudioSessionCategoryOptions = NSInteger; AVAudioSessionClass = interface(NSObjectClass) ['{F8B0F7A3-1805-4739-B827-3AE7FFCD20F0}'] {class} function sharedInstance: Pointer; cdecl; end; AVAudioSession = interface(NSObject) ['{C6EAD2A6-DE66-4A80-B019-8564FF6927AF}'] function category: NSString; cdecl; function currentHardwareInputNumberOfChannels: NSInteger; cdecl; function currentHardwareOutputNumberOfChannels: NSInteger; cdecl; function currentHardwareSampleRate: double; cdecl; function delegate: Pointer; cdecl; function inputIsAvailable: Boolean; cdecl; function mode: NSString; cdecl; function preferredHardwareSampleRate: double; cdecl; function preferredIOBufferDuration: NSTimeInterval; cdecl; function setActive(beActive: Boolean; error: PPointer): Boolean; cdecl; overload; function setActive(beActive: Boolean; withFlags: NSInteger; error: PPointer): Boolean; cdecl; overload; function setCategory(theCategory: NSString; error: PPointer): Boolean; cdecl; [MethodName('setCategory:withOptions:error:')] function setCategoryWithOptionsError(category: AVAudioSessionCategory; withOptions: AVAudioSessionCategoryOptions; error: PPointer): Boolean; cdecl; procedure setDelegate(delegate: Pointer); cdecl; function setMode(theMode: NSString; error: PPointer): Boolean; cdecl; function setPreferredHardwareSampleRate(sampleRate: double; error: PPointer): Boolean; cdecl; function setPreferredIOBufferDuration(duration: NSTimeInterval; error: PPointer): Boolean; cdecl; end; TAVAudioSession = class(TOCGenericImport<AVAudioSessionClass, AVAudioSession>) end; procedure TForm1.Button1Click(Sender: TObject); var LSession: AVAudioSession; LErrorPtr: Pointer; begin LErrorPtr := nil; LSession := TAVAudioSession.Wrap(TAVAudioSession.OCClass.sharedInstance); if LSession.setCategoryWithOptionsError(AVAudioSessionCategoryPlayback, AVAudioSessionCategoryOptionNone, @LErrorPtr) then Label1.Text := 'Set category OK' else if LErrorPtr <> nil then Label1.Text := NSStrToStr(TNSError.Wrap(LErrorPtr).localizedDescription); end; -
As Bill said, it's a "we've been given permission" thing. This is not new, however - I think it has been a "thing" for at least a couple of major releases now. Also, you missed my post: https://www.delphiworlds.com/2020/05/its-time-to-get-excited/ 🙂
-
iOSapi_AVFoundation AVAudioSession extension doesn't work
Dave Nottage replied to Rollo62's topic in Cross-platform
Every time you see a NSError** you'll need to replace it with PPointer. Also, if you see: (NSError * _Nullable * _Nullable) (Which amounts to the same thing) I was just pointing out the incorrect declaration; I have not looked at any other aspect as yet. I'll take a look at your example today and see what the problem might be. -
iOSapi_AVFoundation AVAudioSession extension doesn't work
Dave Nottage replied to Rollo62's topic in Cross-platform
I think you mean in iOSapi.AVFoundation.pas. You're working under the assumption that the declaration is correct - it is not. Because the corresponding declaration in Objective-C is: - (BOOL)setCategory:(AVAudioSessionCategory)category error:(NSError **)outError Note the double asterisk. Because the Objective-C bridge is presently unable to handle wrapping this, a PPointer can be used in the way I described in my reply. As an example, see the code for the DownloadableContentPath method in FMX.InAppPurchase.iOS, which uses the setResourceValue method of NSURL, which is declared correctly. It's a QP report either way, however I'm referring to the missing declaration for the setCategoryWithOptionsError method of AVAudioSession (and any others methods that might be needed) in iOSapi.AVFoundation. No, that's not automatic. It would be nice if it were, however translating SDK framework headers is not trivial, and as you've observed declaration errors can happen, and/or the Objective-C bridge needs to be modified to handle situations where needed. Up until 10.3.2 (or somewhere close to that), the bridge could not even handle Objective-C blocks on macOS (it could on iOS). -
On iOS, you cannot do it programmatically without user interaction; namely: if you post a local notification and the user taps the notification.
- 11 replies
-
- ios
- background
-
(and 1 more)
Tagged with:
-
iOSapi_AVFoundation AVAudioSession extension doesn't work
Dave Nottage replied to Rollo62's topic in Cross-platform
It should be: function setCategoryWithOptionsError(category: NSString; withOptions: AVAudioSessionCategoryOptions; error: PPointer): Boolean; cdecl; But you don't show how you're calling it, either. A possible example: var LErrorPtr: Pointer; LError: NSError; ... setCategoryWithOptionsError(CocoaNSStringConst(libAVFoundation, 'AVAudioSessionCategoryPlayAndRecord'), 0, @LErrorPtr); if LErrorPtr <> nil then begin LError := TNSError.Wrap(LErrorPtr); // Deal with LError here end; You should. No. I suggest filing a QP report. -
iOS Bluetooth LE with background-central stops after 1-10 minute
Dave Nottage replied to Rollo62's topic in Cross-platform
My first guess would be that the data rate is too fast for too long, and iOS kills your app. Before I dive headlong into a deeper look, you might want to read this: https://stackoverflow.com/a/34122794/3164070 ..which links to: https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html- 6 replies
-
- ios
- bluetooth le
-
(and 3 more)
Tagged with:
-
Moving on from my prior question, I have posted this on SO, however I've started a new thread here in case someone that can help might otherwise miss it 🙂 My prior question here: Post on SO for the current problem: https://stackoverflow.com/questions/61514990/setting-an-enum-property-on-a-net-object
-
Thread programming without sleep or WaitFor events
Dave Nottage replied to turkverisoft's topic in Delphi IDE and APIs
Then you should not be using UDP, since order of packets is not guaranteed. With UDP, every packet should be considered data independent of all others. -
WebBroker option not visible in File > New > Other >Delphi projects after installing Delphi 10.3.3
Dave Nottage replied to Ramu's topic in Delphi IDE and APIs
It's not entirely obvious from File|New|Other|Delphi. From there, select the Web folder, and Web Server Application. They're all WebBroker solutions, but that's also not obvious until the second page. -
I have some .NET interop code where I've managed to load objects and read properties, however I am having trouble with setting a property on an object. Here's the relevant parts of the Delphi code: uses mscorlib_TLB, Winapi.ActiveX; type // Irrelevant parts of the code omitted TDotNetObject = class(TObject) private FTarget: OleVariant; FType: _Type; public procedure SetProperty(const APropertyName: string; const AValue: OleVariant; const AIndex: Integer = -1); end; function VariantToPSafeArray(const AValue: Variant): PSafeArray; begin Result := PSafeArray(VarArrayAsPSafeArray(AValue)); end; procedure TDotNetObject.SetProperty(const APropertyName: string; const AValue: OleVariant; const AIndex: Integer = -1); var LPropertyInfo: _PropertyInfo; LIndex: PSafeArray; begin if AIndex >= 0 then LIndex := VariantToPSafeArray(VarArrayOf([AIndex])) else LIndex := nil; LPropertyInfo := FType.GetProperty(APropertyName, BindingFlags_Instance or BindingFlags_Public or BindingFlags_NonPublic); if LPropertyInfo <> nil then LPropertyInfo.SetValue(FTarget, AValue, LIndex); end; procedure UpdateDefectStatus(const ADefectID, AStatus: Integer); var LObject: TDotNetObject; begin // ** Code to obtain the object omitted *** LObject.SetProperty('Status', AStatus); end; An error is thrown when LPropertyInfo.SetValue is called in TDotNetObject.SetProperty: The Status property type in C# is declared: public enum DefectStatus { /// <summary> /// Defect Reported. /// </summary> Reported, /// <summary> /// Defect assessed. /// </summary> Assessed, /// <summary> /// Defect on work order. /// </summary> OnWorkOrder, /// <summary> /// Defect closed. /// </summary> Closed } I found a solution for how to handle this situation using C# here: https://stackoverflow.com/a/13270302/3164070 However I'm a bit lost as to how to do the same in Delphi. Any ideas?
-
Setting a "nullable" property on a .NET object
Dave Nottage replied to Dave Nottage's topic in Windows API
I've posted a new question after help from Olivier: https://stackoverflow.com/questions/61514990/setting-an-enum-property-on-a-net-object If anyone can help, it would be greatly appreciated. -
WebModu class does not exist in Delphi 10.3
Dave Nottage replied to Ramu's topic in Delphi IDE and APIs
The recommended thing to do is to migrate to IntraWeb (from WebSnap, which is where WebModu is from) -
NSHighResolutionCapable = true scaling problems on MacOS 10.13
Dave Nottage replied to Chris Pim's topic in FMX
I followed this link to here: https://quality.embarcadero.com./browse/RSP-27197 I'd use the change that Erik suggested. -
Setting a "nullable" property on a .NET object
Dave Nottage replied to Dave Nottage's topic in Windows API
I've posted a question about this on SO which has received some attention: https://stackoverflow.com/questions/61334031/setting-a-nullable-property-on-a-net-object ..and I think I may be closer to a solution. Can someone check the code for the InvokeToObject method to see if I'm missing anything critical? -
Howto call initWithDelegate and CBCentralManagerOptionShowPowerAlertKey
Dave Nottage replied to Rollo62's topic in Cross-platform
They're ugly, but they are true. In your case however you should need only use dictionaryWithObject (since there is only one value), thus: var LDict: NSDictionary; LBooleanValue: Pointer; begin LBooleanValue := TNSNumber.OCClass.numberWithBool(True); LDict := TNSDictionary.Wrap(TNSDictionary.OCClass.dictionaryWithObject(LBooleanValue, NSObjectToID(CBCentralManagerOptionShowPowerAlertKey))); end; -
Has the relevance of UIRequiredDeviceCapabilities changed since IOS13 ?
Dave Nottage replied to Rollo62's topic in Cross-platform
You'll need to be more specific.- 4 replies
-
- firemonkey
- bluetooth-le
-
(and 1 more)
Tagged with:
-
Excellent! I was not aware of that property; thanks 🙂
-
I see what the problem is now: it's because selecting Segoe UI at design-time results in the Family value not being stored in the .fmx, because it's the default for Windows. I'd consider that a design fault, since it does not account for using a font with the same name on platforms other than Windows. Easiest solution: use something that looks like Segoe UI, but isn't 🙂 Any other solution would seem a bit difficult..
-
That's because you have Family in the StyledSettings property set to True in the Object Inspector (i.e. at design time). You need to set it to False
-
It also works for me just by having the Font.Family property in TextSettings set to the correct value (i.e. Anton) at design time. Using the button and code was just to demonstrate that there's a very obvious change in the font. I suspect there's something else wrong with your project, which is why I asked to post a test case.
-
I'm using Delphi 10.3.3, the latest released version of Xcode (11.4), building against the latest iOS SDK (13.4) and it works on my iPhone X which has iOS 13.4. I've attached my test project (which uses the Anton font, from here: https://fonts.google.com/specimen/Anton). Perhaps if you have a test project, you could attach it so it might be discovered what is going wrong. CustomFontDemo.zip