Re: [push-api] Add optional userVisibleOnly parameter to register & hasPermission (#87)

***tl;dr: In order for UAs to be free to implement any of 2, 3a, 3b, 3c or 3d etc, we need to have two different ways of requesting push permission. How about `PushManager.requestSilentPermission()` and `PushManager.requestUserVisiblePermission()`?***

@martinthomson wrote:
> we couldn't rely on [notifications as a form of feedback] alone (notification UX being outside our control on some platforms). And limited real estate means that there may simply be too little space anyway. Not saying that it isn't worth looking into though.

It should be possible on Android 4.1+, Firefox OS, and several desktop platforms at least. On JellyBean+ we plan for notifications to always show the origin, and additionally show a Site Settings button when you expand a notification, and on Lollipop+ we'll additionally show a settings cog when you long-press on the notification. The button and cog will both deep-link to the content settings page for the origin that showed the notification, allowing you to revoke the permission.

> 3c. (...) It's the opposite: if you can do push, you can notify everywhere. But the existing Notification permission is unchanged here. The argument for this case is that we don't change the meaning of an existing consent grant, but merely add another one that provides a wider scope.

Gotcha, that makes more sense (especially with the code samples - thanks!).

> > Can I ask how you would you represent option 3b in the API?
> I'd simply have the two permissions orthogonal from an API perspective. Rather than gate access to the SW on the "background" permission, I would also allow it when the "notification" permission was active 

But wouldn't spec'ing things that way prevent UAs from implementing 3c (since developers would incorrectly assume that having notification permission meant they would be able to use push notifications)?

We can debate for days which model is the best tradeoff, but my goal is to get to a place where the specs allow UAs to implement any of 2, 3a, 3b, 3c or 3d etc (and evolve this over time) yet have the same JS work in all browsers (without unnecessary prompts).

Suppose we had the following strawman API:
```js
partial enum PermissionName {
    "notifications",
    "user_visible_push_messaging",
    "silent_push_messaging",
    "background_sync"
}
[Exposed=Window]
partial interface Permissions {
    // Returns a sequence of Promises, since some may be resolved earlier than
    // others if multiple prompts are shown.
    static sequence<Promise<PermissionState>> request(PermissionName... name);
}
```

Then ideally each of the following JS snippets would "do the right thing" in all UAs:
```js
// A. Notifications shown from a foreground window/worker only (though the
// notifications themselves may be persistent).
Permissions.request("notifications").then(...);

// B. Notification-only Push (some browsers will force these to show a
// notification for almost every push).
Promise.all(Permissions.request("notifications",
                                "user_visible_push_messaging")).then(...);

// C. A mix of silent push and push notifications (browsers will never force
// these to show a notification).
Promise.all(Permissions.request("notifications",
                                "user_visible_push_messaging",
                                "silent_push_messaging")).then(...);

// D. Silent push messaging.
Permissions.request("silent_push_messaging").then(...);

// E. Background sync.
Permissions.request("background_sync").then(...);

// F. Silent push and background sync.
Promise.all(Permissions.request("silent_push_messaging",
                                "background_sync")).then(...);

// G. Gimme everything!
Promise.all(Permissions.request("notifications",
                                "user_visible_push_messaging",
                                "silent_push_messaging",
                                "background_sync")).then(...);
```

Specifically if Chrome chooses to implement 3b:
- A, B would show a push notifications prompt
- D, E, F would show a background prompt
- C, G would show both a notifications and a background prompt (either combined, or one after the other)

And if Firefox chooses to implement 2:
- A would show a notifications prompt
- D, E, F would show a background prompt
- B, C, G would show both a notifications and a background prompt (either combined, or one after the other)

Or if Firefox chooses to implement 3c:
- A would show a notifications prompt
- B, C, D, E, F, G would show a background prompt

Another UA might choose to grant background_sync for free to any website that asks for it, yet prompt for silent_push_messaging (on grounds that the UA can throttle background_sync at will, but can't throttle silent_push_messaging without dropping possibly important messages).


However such a strawman extension to the [Permissions API](https://w3c.github.io/permissions/), would be a rather large dependency; in the meantime, the same effect could be achieved with existing APIs using independent* method calls like `Notification.requestPermission()` to request each of notifications, user_visible_push_messaging, silent_push_messaging and background_sync. It's already possible for browsers to detect when several permissions are synchronously requested without returning to the message loop (permission requests don't block each other of course, since they're all async), and in such cases they can coalesce the prompts however they choose.

With the currently spec'ed APIs, it's thus already possible to implement 2, 3a, or 3c. Unfortunately UAs can't yet implement 3b or 3d, since there's no distinction between user_visible_push_messaging and silent_push_messaging. Hence this pull request seeks to introduce such a distinction, allowing all five policies to be implemented.

It seems you're not keen on the current patch's approach of treating user-visible-push and both-silent-and-user-visible-push as two different levels of the same permission. Would it be better to explicitly split them out as follows?:
```js
interface PushManager {
    Promise<PushRegistration> register ();
    Promise<PushRegistration> getRegistration ();
    Promise<PermissionStatus> requestSilentPermission ();
    Promise<PermissionStatus> requestUserVisiblePermission ();
    Promise<PermissionStatus> hasSilentPermission ();
    Promise<PermissionStatus> hasUserVisiblePermission ();
};
```

Then for example developers would implement G. Gimme everything as:
```js
Promise.all([
    Notification.requestPermission(), // Technically this doesn't yet return a Promise
    pushManager.requestSilentPermission(),
    pushManager.requestUserVisiblePermission(),
    syncManager.register(id, options) // We could add a requestPermission method to the spec instead
]).then(...);
```

*: (To ensure that authors write JS that will work in all UAs, rather than hardcoding the current UX choices of the browser(s) they test in, UAs should probably return "prompt" when a permission has not yet been asked for, even if previously granted permissions mean the prompt will be automatically granted without bothering the user. We should probably spec that.)

---
Reply to this email directly or view it on GitHub:
https://github.com/w3c/push-api/pull/87#issuecomment-67082743

Received on Monday, 15 December 2014 22:59:18 UTC