WebBluetoothCG / web-bluetooth

Bluetooth support for the Web.
http://www.w3.org/community/web-bluetooth/
Other
1.38k stars 187 forks source link

optionalServices is not very clear #82

Closed kenchris closed 9 years ago

kenchris commented 9 years ago

I fail to understand the point? Is it to be understood, that the optional services UUIDs also show up in the dialog to the user but marked as 'not required' but 'usable' devices?

Why not just add it to the BluetoothScanFilter instead?

dictionary BluetoothScanFilter { sequence requiredServices; sequence optionalServices = []; };

Also why is filters a sequence of sequences of UUIDs?

jyasskin commented 9 years ago

The idea for optionalServices is that it lets the UA know the complete set of services a website wants to use. This will let us give the site an early error if it intends to access a disallowed service, and could eventually let us include a description of exactly what the site wants to do with the selected device in the requestDevice dialog.

Only the filters affect the set of devices shown in the dialog. Both the filters and optionalServices determine the allowed services list.

filters is a sequence of sequences because a site might be able to use several different kinds of devices, so we need some way of saying "I need a device that supports {X and Y} or that supports {Z and W}".

We could add optionalServices to the filter: it would let a site say "for devices that have these services, I can also take advantage of these other ones" instead of just listing all the extra services the site can take advantage of. This would complicate the assignment to the allowed services list, since we'd need to say what to do for devices that support all of X, Y, Z, and W when their optional services are different. Do we grant access to the union? How would that look in a UI? It seemed simpler just to put the whole set of services in a single bag.

I have been thinking of combining the two arguments into a single dictionary. requestDevice([{services: [x, y]}], {optionalServices: [a, b]}) makes it easy to put things in the wrong set of brackets. requestDevice({filters: [{services: [x, y]}], optionalServices: [a, b]}) might be easier to read and write.

kenchris commented 9 years ago

Oh, so it is basically a list of all services you want to use any time in the future, and which ones are hard requirements. Maybe "optional" is not the best word then.

so for {filters: [{services: [x, y]}, {services: [i, j]}], optionalServices: [a, b]},

could there be a device that didn't support say [x, y] or [i, j] but supports [a]? Or would that be ignored if it didn't also support the [x, y] or the [i, j] pair?

It kind of feels like the user lists the services that he/she is requesting permission for, and then also list which ones are hard requirements - but that you want to avoid listing some twice.

I understand the problem if the optional services are part of each set of required ones, but always allowing the optional ones doesn't seem right to me either. Who says that the optional services are less of a risk?

jyasskin commented 9 years ago

The device would be ignored if it doesn't match one of the filters, even if it supports all of the optional services.

It kind of feels like the user lists the services that he/she is requesting permission for, and then also list which ones are hard requirements - but that you want to avoid listing some twice.

That's right. It also seems like it'd be weird to say that a service is a hard requirement, but then not ask permission to use it. Having separate lists allows that sort of inconsistency.

I don't think the optional services are less of a risk. It's more that if we put optional services in each filter, the gain is that we can tell the user: "foo.com will have access to Innocuous Service if you select Device A, but Dangerous Service if you select Device B." It seems like users will tend to miss services in such a complicated UI, so the gain there seems small. Moving the optional services to be per-filter would also require developers to list them multiple times, so there is a loss, which isn't counteracted by the small gain. We can put the optional services in both places, but we can also do that later, when the need arises.

This all definitely deserves an example in the spec.

kenchris commented 9 years ago

I definitely get the point of not listing it twice, but it might be possible to annotate the services, like { service: x, optional: true } or similar, but as you said, that might mean that people might miss a few services.

I agree that this definitely needs examples.

So what if I have a devices only supporting some of the optional services? Would that always be useless? because as I understand it, such a device would be ignored with the current API, right?

jyasskin commented 9 years ago

If you have a device supporting a whole filter and some of the optional services, e.g. it supports services, A, D, X, and Y, and the call is requestDevice([{services: [X, Y]}], {optionalServices: [A, B, C]}), then the device will show up in the dialog, and if the user selects it, the website will have access to services A, X, and Y. Not D because it's not in optionalServices, and not B or C because those don't exist on the device. If the device is later updated to include B or C, the site would get access to those without an extra prompt.

kenchris commented 9 years ago

But if I have a device which only supports [A, B] which is optional, ie it doesn't support X and Y. Then it will be ignored right.

or I will have to add [A, B] as required services, ie

requestDevice([{services: [X, Y]}, {services: [A, B]}])

But then if I have a device support X, Y and B, then that device would not be able to use B,

unless I duplicate it and add it as optional as well

requestDevice([{services: [X, Y]}, {services: [A, B]}], {optionalServices: [A, B]})

jyasskin commented 9 years ago

That's mostly correct, except the requestDevice() algorithm says

8) Add device to the origin's allowed devices map. with the union of the service UUIDs from filters and options.optionalServices as allowed services.

so with requestDevice([{services: [X, Y]}, {services: [A, B]}]) the site will still have access to B on the {X,Y,B} device. I could imagine this mattering if a fitness site wants to add either step trackers or heart rate monitors, but would be happy to use both on a device supporting both.

kenchris commented 9 years ago

Ah I see. I think adding examples, like these in questions in this GitHub issue, would really help making this clear.

Maybe we should call optional for additionalServices instead. In the {X, Y, B} example, B is just as optional, but if we call it additionalServices, it is more obvious that they are added to the poll of services which are allowed/can be used.

jyasskin commented 9 years ago

The examples here have been great, thanks! I'll use them to inspire the spec examples.

additionalServices sounds reasonable to me. I'd like to get a couple more folks to weigh in on that bikeshed color before picking one.