ANCS Support
This PR Adds support for the Apple Notification Center Service (ANCS). It shows the Title and Subtitles as "Title - Subtitle" and the message is shown in the body of the InfiniTime notification. Accepting and Declining calls also worked.
The only "issue" right now is that you have to ReConnect after the first pair for ANCS discovery to go well. Maybe there is a way in the NimBLE stack to trigger ANCS Discovery after pairing change? Also, sometimes ANCS goes dormant and then works again. I think this could either be iOS throttling or
"ANCS is not guaranteed to always be present. As a result, the NC should look for and subscribe to the Service Changed characteristic of the GATT service in order to monitor for the potential publishing and unpublishing of the ANCS at any time."
Build size and comparison to main:
| Section | Size | Difference |
|---|---|---|
| text | 390460B | 8544B |
| data | 944B | 0B |
| bss | 22736B | 120B |
For reference, closes #910
Instructions: since an encrypted connection is required before ANCS is available, you’ll need to disconnect your watch from your companion app after updating, then reconnect. You’ll get a passkey on your watch to enter into the dialog on your iPhone. After bonding, toggle off and on your iPhone’s Bluetooth, then tap InfiniTime in the list of bonded devices. Finally, you’ll get an alert asking you to allow your watch to read notifications. Click allow, and now you should start receiving notifications!
Something to note: as of now, since using ANCS creates a connection through iOS directly instead of through the companion app, the app will not be able to reconnect to InfiniTime without removing the bond, which results in ANCS being disabled until the steps above are repeated. We’re working on fixing this ;)
Update: this is fixed in the latest InfiniLink commit on the rebuild branch
Does this implement subscribing to service changes? I think this is probably required given the ANCS can come and go at any time
I think the implementation of this is relatively simple, subscribe to the generic attribute service changed characteristic, and any time an indication is received service discovery should be performed again
@mark9064 I didn't explicitly implement the service changed part, but in all my testing the watch was always able to recover from a disconnect and showed new notifications. So maybe there is something in the stack that handles this?
I don't believe it's handled elsewhere, but it could be? The text you quote at the top, about the service being registered/unregistered, isn't talking about bluetooth disconnects but actually the service itself disappearing from the list of services the apple device exposes, and then re-appearing at some later time. Maybe in practice apple devices never really do this (even though the spec allows them to), so you don't observe any issues. But I think it would be wise to have this base covered if the standard allows it
How long did you test it? Could it be that the service disappears after a few hours?
I'm able to use this for multiple days at a time without missing a notification.
According to the logs, the watch is (very frequently) not able to subscribe to the data source, but always recovers before the next notification is sent.
Thank you for implementing this, @cyberneel! I just typed the secure connection code into my iPhone for the first time, am already a little hyped from that and will test this PR over the next week :)
Yes, it is really impressive that you did it. Thank you!
Yesterday I found that we have no-device support for German umlauts öäü and other such characters. Since the notifications come directly from iOS, we have to discuss how far we can and want to go on the watch.
But that would be no blocking issue for this PR from my side as long as the BLE service works fine otherwise. So maybe discuss this in the linked issue instead of here.
My test over the last week was very positive. Great job! Feature-wise I would merge it as is, but haven't looked at the code in detail yet and will hopefully do so in the next days.
I don't know if this helps, but I've been running this branch on my PineTime and I have been encountering an occasional crash and reboot. I don't know if it's related to the changes here. Is there anything I can provide that would help the development efforts here? Some sort of log in a version of InfiniLink maybe?
I don't know if this helps, but I've been running this branch on my PineTime and I have been encountering an occasional crash and reboot. I don't know if it's related to the changes here. Is there anything I can provide that would help the development efforts here? Some sort of log in a version of InfiniLink maybe?
Can confirm this on a fork of mine including ANCS
I'm more than willing to provide logs and debug information to help resolve the issue. Does the watch record any logs, or is that something a companion app can provide?
Hello everyone,
I've been very busy since I made this PR with school and other commitments.
Most of the base for my code was adapted from the existing notification service meant for android. So there are probably many places I could have optimized.
I plan on responding to code reviews in the coming weeks to give everyone a better understanding of the code. This could help narrow down possible cause of the reboots.
Thank you everyone for your support!
Thank you everyone for your support!
Thank you for your support! ;)
I hope I can find some time next weekend for further review. It's been a while. Sorry for that.
I am still running this branch all the time. I noticed one crash in the meantime, although more might have happened, because I wouldn't have noticed as long as the watch reconnected and reset its time correctly after rebooting.
I am overall very positive, still have to review the last half of the code (sorry), but would say that this PR is totally usable and I would already in this state recommend it to anyone using a PineTime with iOS.
Let's both find the time to review it (reviews from others who want to help are welcome as well 🙂) and this is on a good way to be merged.
Also please update this branch to the current main.
Also please update this branch to the current main.
I can take care of that :)
@minacode Thank you! I am on break from school now so I have some time. I can start looking at the code review and make comments.
I'll update the branch soon.
Not sure what's up with clang-tidy, unless there's a submodule update github isn't showing? Could you fix the code formatting?
I updated the branch and am trying to fix a weird behavior.
Sometimes, notifications are pinged on the watch multiple times as duplicates. I tried addressing this through checks to make sure the notification is new and not old but it is not working fully.
Would love to hear if anyone has any insight or observations to add to this.
I've noticed this as well...
Nothing changes when they're sent again, like any flags, etc.?
I have to test more, but this ping happens in the datasource handler. And the datasource doesn't provide flag information.
The notification source handler has a return statement if it's not a new notification source it doesn't request datasource at all.
I think possibly datasource is sending multiple times some times for some reason. I'll see if check if uuid exists in notification manager fixes it.
I don't know if this helps, but I've been running this branch on my PineTime and I have been encountering an occasional crash and reboot. I don't know if it's related to the changes here. Is there anything I can provide that would help the development efforts here? Some sort of log in a version of InfiniLink maybe?
For anyone experiencing this as well, I've done some testing and found a way to, in my case, 100% reliably cause a watchdog reset.
Step 1: Do all the ANCS connection stuff so that your watch mirrors your phone's notifications like usual Step 2: Send lots of very long messages. I tried it with roundabout 15 messages, 2000 characters each message. I'm not sure if this is necessarily needed, since the watch only stores 5 notifications and each one gets cut off after some hard-coded character limit, but that's what I tested it with. Step 3: Go into your iPhone's Bluetooth settings and toggle it off and on pretty frequently. In my case, once the watch showed the little Bluetooth symbol in the status icons, I turned Bluetooth off and when it was gone, I turned it back on. I did that just to make sure it was definitely reconnecting each time. Step 4: After about 15 - 20 seconds, the watch will freeze and cause a watchdog reboot
Now, I'm not an expert in ble logic, infact I don't really know anything about it, so this is where my side of the info stops. I hope someone else that knows more about it can profit from this test and figure out a fix.
@tituscmd how are you sending these messages (in step two)?
@tituscmd how are you sending these messages (in step two)?
I made a friend send them over WhatsApp to make sure it's related to ANCS and not InfiniLink
After further investigation, notifications in the Notification Center don't matter. It's just the reconnection that's causing it
So is it good to merge? My PineTime watch has been getting dust ever since I got an iPhone and this was my only hope but it doesn't get merged...
There are still crashes. The good news is that InfiniTime is robust enough that you won't notice them if you don't look at the screen during the reboot that happens after a crash. While we are not ready for merging yet, I am already running this branch for a long time and it does the job well enough to use it in daily life. So try it out! 🙂
I noticed the crashes to happen when I have a greater distance to my phone, so I think the BLE reconnection theory is correct. Since this doesn't happen on the main branch, I suspect it has to do something with the discovery of this service. In the docs, Apple does not guarantee all the characteristics or services to be available. Maybe we have to harden the connection code for ANCS more.