Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Apple Notification Center Service Implementation #1

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

scandinave
Copy link
Owner

@scandinave scandinave commented Feb 14, 2022

This PR enable support of Apple Notification Center Service. The current state of this PR is as follow :

  • Create initial mapping for ANCS event
  • Map ANCS Characteristic UUID
  • Initial implementation for notification source characteristic
  • Replace default alert implementation by ANCS when connected to a apple device
  • Enable and test encryption on ANCS characteristic
  • Use Service Changed characteristic
  • Implement usage of control point characteristic
  • Implement usage of Datasource characteristic
  • Build a setup to debug on pinewatch

@scandinave
Copy link
Owner Author

At this time, i have not test the current implementation against the watch. I'm waiting for the missing part that will allow me to connect it to my PC.

Works was made based on the existing AlertNotificationService

@minacode
Copy link
Collaborator

minacode commented Feb 15, 2022

I saw that you mapped the notification categories from Apple to the ones from InfiniTime. Since Infinitime only checks for IncomingCall and ignores the rest by now, I think we can just add the categories from Apple.
Those would be Social, HealthAndFitness, BusinessAndFinance, Location and Entertainment.

@scandinave
Copy link
Owner Author

if we left the mapping in place, when other types of notification will be available, this will be handle automatically no?

Is it to save some storage size that you want to remove this mapping? I'm not a expert in embedded dev. I mostly work with java and JS.

@minacode
Copy link
Collaborator

I am also new to embedded C++ and mostly use Rust and Python.

No, the mapping is fine. I was just wondering if we should add the missing categories from Apple to NotificationManager.h

@scandinave
Copy link
Owner Author

OK. i think, this could be in another PR. The priority is to implement the notification . this will be more easily for the reviewer if with stay with the bare minimal.

@scandinave
Copy link
Owner Author

Little things to note :

  • I have rebase the branch against upstream so you will have to do a reset --hard of your local copy.
  • I fixed characteristics definitions that was not correctly handle. Instead of 3 characteristics, we have one with 3 services. We now have only one callback function available and need to find a way to discriminate the services that is called.
  • In displayApp.cpp, there is L370, an instanciation of the Notifications App. I thinks we need to find a way to replace this instanciation with the ANCS implementation, only, if we are paired with an iphone. Don't know at this moment how to do that :)
case Apps::Notifications:
      currentScreen = std::make_unique<Screens::Notifications>(
        this, notificationManager, systemTask->nimble().alertService(), motorController, *systemTask, Screens::Notifications::Modes::Normal);
      ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
      break;
case Apps::NotificationsPreview:
      currentScreen = std::make_unique<Screens::Notifications>(
        this, notificationManager, systemTask->nimble().alertService(), motorController, *systemTask, Screens::Notifications::Modes::Preview);
      ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp);
      break;

@minacode
Copy link
Collaborator

I fixed characteristics definitions that was not correctly handle. Instead of 3 characteristics, we have one with 3 services. We now have only one callback function available and need to find a way to discriminate the services that is called.

This seems a little weird to me, since the Apple docs say:

The Apple Notification Center Service is a primary service whose service UUID is 7905F431-B5CE-4E99-A40F-4B1E122D00D0.

and

In its basic form, the ANCS exposes three characteristics:

  • Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable)
  • Control Point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response)
  • Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable)

Am I missing something?

In displayApp.cpp, there is L370, an instanciation of the Notifications App. I thinks we need to find a way to replace this instanciation with the ANCS implementation, only, if we are paired with an iphone. Don't know at this moment how to do that :)

I will look into that. Maybe we can keep the standard notification service :)

@scandinave
Copy link
Owner Author

Ok my bad. I have invert the hierarchy of service and characteristics. I will revert the change.

@minacode
Copy link
Collaborator

Dont worry, we are both new to this and learning, I guess 😄

@scandinave
Copy link
Owner Author

Do you think ControlPoint characteristic need to be defined in our side ?

Per Apple docs An NC can issue a request to retrieve more information about an iOS notification by writing specific commands to the Control Point characteristic. If the write to the Control Point characteristic is successful, the NP will promptly respond to the request through a stream of GATT notifications on the Data Source characteristic.

This seems to be the role of the watch to contact iphone by writing on the characteristic. This doesn't make sens to me to add callback for this characteristic

@minacode
Copy link
Collaborator

I am not sure if we need some kind of definition our side to write to it. If not, we don't need it.

@minacode
Copy link
Collaborator

Regarding the service, I think we need a flag on notifications to mark if they are normal or from Apple and some kind of intermediate that handles them with the correct service-backend.

@scandinave
Copy link
Owner Author

If you have an hint on how to configure Clion for this project, i will take it :) .

@minacode
Copy link
Collaborator

No, I am sorry 😐 All I know is the .idea folder.

@minacode
Copy link
Collaborator

minacode commented Feb 17, 2022

The last commit makes everything compile with docker, but be aware of this unmerged PR.
I flashed it to my watch and used a little shortcut on my iPhone to generate notifiations in iOS. So far, the watch does not respond to it.

Also: There is an AlertNotificationClient and I guess that this is what we should copy for the control point characteristic.

@scandinave
Copy link
Owner Author

I compile with native Cmake so no problem for me.
I'm waiting for the last piece to be delivered to me, to be able to debug the watch.

I will take a look at AlertNotificationClient

@minacode
Copy link
Collaborator

minacode commented Feb 18, 2022

This issue and apple indicate that ANCS needs secure bonding/pairing. That can be obtained by forcing encryption on the ANCS. If we get this to work, then we should hopefully be able to get simple dummy notifications on the watch.

@scandinave
Copy link
Owner Author

scandinave commented Feb 18, 2022

How do you flash it to the phone? Using OTA with compagnion app?

I think the AlertNotificationClient is use when we want to send notification from the watch to the phone. If i'm rigth there is no need to handle it at this time

@minacode
Copy link
Collaborator

minacode commented Feb 18, 2022

I flash build/output/pinetime-mcuboot-app-dfu-1.8.0.zip with OTA via siglo. Do you know a better or faster way to do this? It takes ~20 min to flash the image

@scandinave
Copy link
Owner Author

i think you can do it via OTA by installing infinilink compagnon app

@minacode
Copy link
Collaborator

I tested yesterday to generate "Hello World" notifications on the watch whenever any incoming notification is detected. That did not work.
Today, I wondered if we implement the wrong half of the protocol and implemented a simple client, based on AlertNotificationClient to do the same. This did also not work. Is it ok if I push all of it?

@scandinave
Copy link
Owner Author

scandinave commented Feb 18, 2022

of course you can :)

I just push an update for the flag on characteristic to enable secure connection. For this I have found the PR that has make it work in the past. Maybe you can try with this.

@scandinave
Copy link
Owner Author

Yes. We need this check this and find a way to replace current alert implementation by ours when connected to apple device

@minacode
Copy link
Collaborator

I tried to add the ANCS next to the ANS. Do they interfere somehow?

@scandinave
Copy link
Owner Author

we need to test. data received are not the same

@minacode
Copy link
Collaborator

They have different UUIDs, so I do not suspect a problem.

@scandinave
Copy link
Owner Author

Yeah you are right. We will have hard time to test this is we need a secure connection that is not available for the Infinilink App. Maybe we need to make another PR to address this issue first ?

@minacode
Copy link
Collaborator

minacode commented Jun 8, 2022

Hi, its been some time. I am currently working on my thesis and do not habe much time. Here are my current thoughts:

We separately need to implement the GenericAttribute Service (0x1801) and its ServiceChanged characteristic.
We then need to implement ANCS in a way that we can mark it as "off" and also can reinitialize it (or maybe just turn it "on" again?) when it appears again.
I am not quite sure yet, where this mechanic would be handled best.

I also never got to the point where the watch paired with my iPhone.

@AsafFisher
Copy link

Is anyone working on it? Can I finish this?

@minacode
Copy link
Collaborator

minacode commented Jul 3, 2022

No, not right now. Feel free 😊


int AppleNotificationCenterClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error* error, uint16_t characteristicValueHandle, const ble_gatt_dsc* descriptor) {
if (error->status == 0) {
if (characteristicValueHandle == notificationSourceHandle && ble_uuid_cmp(&notificationSourceChar.u, &descriptor->uuid.u)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the last comparison needed?
This callback is called only for notificationSourceChar's descriptors, no?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to recall this. This handles the notification subscription, right? Then we also want this for the dataSourceChar as well, but this code as it is just tries to detect an incoming message and then to show a dummy "Hello World" Notification. So this should stay in, because later on, there will be another case.

@AsafFisher
Copy link

AsafFisher commented Jul 12, 2022

Seems like the watch does not advertise itself properly causing the service discovery to return unlikely error, I'll keep investigating next mont how to properly setup the watch so it will be discoverable by the IOS device
I think the problem lays in the open source NRF impl

@jnovek
Copy link

jnovek commented Jul 13, 2022

@AsafFisher anything I can do to help? I’m a backend web dev mostly but I dabble. :-)

My pebble stopped working and I don’t want to buy an Apple Watch. Notifications are the only thing stopping me from using PineTime full time.

@minacode
Copy link
Collaborator

You could take a look at the GATT Service and its service changed characteristic.
See my posts on the issue. We need to be able to turn ANCS on and off at any time. Especially, because it may not be available directly after connection.

@AsafFisher
Copy link

I understand that the BLE pairing is not encrypted, am I right?

@minacode
Copy link
Collaborator

I don't know. Maybe you should ask this in the InfiniTime repo.

@jnovek
Copy link

jnovek commented Jul 14, 2022

You could take a look at the GATT Service and its service changed characteristic.

👍 I’ve never worked with BLE but I don’t mind giving this a try, with the caveat that someone with more experience can feel free to beat me to a solution. :-)

I’ll get the project running today and tomorrow in my free time and dig around some over the weekend.

Y’all got a discord or IRC?

@AsafFisher
Copy link

AsafFisher commented Jul 14, 2022

Doesn't fields.uuids128 additionally to the dfu service need to contain the ANCS service uuid?

@AsafFisher
Copy link

You could take a look at the GATT Service and its service changed characteristic.

👍 I’ve never worked with BLE but I don’t mind giving this a try, with the caveat that someone with more experience can feel free to beat me to a solution. :-)

I’ll get the project running today and tomorrow in my free time and dig around some over the weekend.

Y’all got a discord or IRC?

There is an Element group chat, me and some others are active there.

@minacode
Copy link
Collaborator

👍 I’ve never worked with BLE but I don’t mind giving this a try, with the caveat that someone with more experience can feel free to beat me to a solution. :-)

There are services which have characteristics (that hold the values) which have descriptors that you mostly only need to subscribe to a characteristic.

I far as I understand it, the Gatt service has a ServiceChanged characteristic that gives you a range of affected handles (kind of like a reference of the service on your device) for services that changed. You can compare this to the handle attributes of the ANCS class and invoke a reaction such as en-/disabling ANCS.
The same mechanic would also be useful for the AppleMediaService in the future.
No guarantee, because I obviously didn't do it 😉

@AsafFisher
Copy link

Funny that you say that, I tried it yesterday (:
Didn't work hehe

@minacode
Copy link
Collaborator

minacode commented Aug 3, 2022

Any updates?

@jnovek
Copy link

jnovek commented Aug 3, 2022

I’m still interested in helping out with this but I was knocked over by COVID the weekend after my comment. I’m playing catch-up at normal life things and still pretty tired. Sorry I didn’t say anything sooner!

@Nobody2303
Copy link

Hello everyone,

are there any recent updates on things tried to push these topics any further?

I'm willing to contribute some time on the pinetime FW front for integration of the ANCS as well as GATT handling.

Also further links to specifications, especially SW architecture descriptions are highly appreciated.

@minacode
Copy link
Collaborator

minacode commented Nov 2, 2023

Nothing new, sadly. You can find most information here or in the issues and pull requests regarding iOS on the InfiniTime repo.

Main problem: the services Apple devices expose can (and will) appear and disappear. InfiniTime can't handle this right now.
The rest is probably the not so great BLE debugging experience. You cannot debug on your phone and not easily on the running watch. Maybe it's better with a dev set, but I don't have one and can't tell.

But feel free, I think some of the code here is useful 😊 Would be nice if someone gets it running.

@Nobody2303
Copy link

Nobody2303 commented Nov 3, 2023

So in general we would need some kind of internal state machine to keep track of, are we paired with an apple device and if so another state machine to keep track of services the paired device once provided as they might reoccur anytime... and which are availlable right now. Or am I following a misconception here that simply keeping track of what has been there is not enough to ensure proper handling as soon as the service reoccurs on the Apple Device side?

Also I think actual changes should be done on the main repo, or would it make sense to rebase this fork to the current main repo state to ensure everything is working well together on the latest version availlable?

@minacode
Copy link
Collaborator

minacode commented Nov 3, 2023

Tbh, I think this fork here is dead.

The behavior is normal BLE and the documentation says that there is a service where the changes regarding availability of other services are published. Apple are just using it all, instead of the others. Have you found the other discussions over at the original repo? I believe that I answered some questions there before.

Edit: for example this one.

@Nobody2303
Copy link

Nobody2303 commented Nov 4, 2023 via email

@OctopusET
Copy link

Replace default alert implementation by ANCS when connected to a apple device

I think this part can be changed in InfiniLink app
https://github.com/InfiniTimeOrg/InfiniLink/blob/32cd805a4eb21cc4ab646c409e72be5284dcf3d0/InfiniLink/BLE/BLEDiscoveredCharacteristics.swift#L46

@minacode
Copy link
Collaborator

minacode commented Jul 8, 2024

No, ANCS is not provided by an app. It comes from iOS itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants