notifications icon indicating copy to clipboard operation
notifications copied to clipboard

Supporting multiple image definitions for a Notification

Open beverloo opened this issue 9 years ago • 62 comments

Currently Notifications support a single image to be defined, but on today's world of many different screen densities we may want to consider a syntax for multiple syntax.

My proposal is to adopt the Web Manifest's syntax for defining an icon size: http://w3c.github.io/manifest/#icons-member

This would look as follows:

registration.showNotification('My Notification', {
  body: 'Hello, world!',
  icon: '/legacy-icon.png',  // optional, only used as fall-back
  icons: [
    { src: '/icon-1x.png',
      type: 'image/png',
      density: 1 },
    { src: '/icon-2x.png',
      density: 2 },
    { src: 'icon.ico',
      sizes: '128x128 256x256' }
  ]
});

On a tangent, we may also want to consider some sort of "small icon", to be used when the platform displays such icons in a status bar. (E.g. my little flag man on Android -- we're going to show a generic Notification icon when shipping them.)

+@mounirlamouri

beverloo avatar Dec 14 '14 15:12 beverloo

I think it's a great idea to re-use the icons syntax from the Manifest.

Though, I'm not sure what we should do wrt the "small icon". What would be the best way to describe this icon? Should that be an icon that represents the website but not the notification? or the type of notification?

mounirlamouri avatar Dec 14 '14 20:12 mounirlamouri

Many applications only use a single icon, usually their logo, as it's a quick indicator for the user that an event in context to that app has happened. From that point of view a site-specific icon could work.

Two notable examples of where offering more freedom would be good would be Gmail, which either displays a single e-mail icon or a stack of e-mail icons depending on the number of messages waiting, or Calendar, which displays a small icon with the current day in the center.

(Chrome won't be able to support this for at least another year, so it's a much lower priority than the current icon in multiple densities.)

beverloo avatar Dec 14 '14 22:12 beverloo

In chrome apps/extensions, we have created the concept of "appIconMask" which is an alpha-only icon that can be used to overlay a solid color. This enables things like the little flag man without too much work on the platform side, since the color information is thrown out anyway.

mrdewitt avatar Dec 15 '14 17:12 mrdewitt

See http://lists.w3.org/Archives/Public/public-web-notification/2014Apr/0012.html though it seems that concern is addressed through density. @zcorpan needs to generalize the images code path so all of this can utilize it.

annevk avatar Dec 16 '14 13:12 annevk

@foolip @richtr Media Session has this problem as well. We should come up with a solution that works for both and elsewhere. Since manifests are still somewhat at risk I'd prefer us reusing a pattern of something that's implemented, like <picture>.

annevk avatar Jul 30 '15 12:07 annevk

Very interesting. Media Session will indeed need this, because you'll want to change the icon of the media playback notification. However, we also want to change the lockscreen background. Both of these are currently in MediaMetadata.artwork, but it would probably make sense to split them into icon and artwork or perhaps background.

It seems like https://github.com/whatwg/mediasession/issues/58 applies very much here as well. How do we expose the load of this kind of multi-image icon, and how do we make it possible to preload the icon using Fetch?

foolip avatar Jul 30 '15 13:07 foolip

@annevk wrote:

I'd prefer us reusing a pattern of something that's implemented, like <picture>.

Do you mean letting icon also take multiple comma-separated image candidate strings in the same way srcset works? I honestly prefer that idea over using the manifest syntax or introducing icons.

richtr avatar Jul 30 '15 13:07 richtr

Why is Manifest "at risk"? It is implemented by Edge, Firefox, Google and Opera and used in the wild.

mounirlamouri avatar Aug 13 '15 16:08 mounirlamouri

A background image could also be used for Wear devices. Currently, they fall back to using the notification icon, but that is often not of sufficiently high resolution, and looks a little blurry.

mvano avatar Jan 18 '16 12:01 mvano

I'd like to split off the discussion of small icons into issue #65.

mvano avatar Mar 10 '16 17:03 mvano

I've been prototyping multiple image definitions in Chrome, and so far the Manifest syntax seems like a good match. The idl would look like this:

dictionary NotificationIcon {
    USVString src;
    DOMString type;
    DOMString sizes;
    double density;
};

dictionary NotificationOptions {
    sequence<NotificationIcon> icons = [];
};

interface Notification {
  readonly attribute sequence<NotificationIcon> icons;
};

mvano avatar Mar 10 '16 17:03 mvano

In order to not duplicate the existing icon properties have you considered using a typedef instead? It's very unlikely that we'll be able to deprecate icon anytime soon.

typedef (USVString or sequence<NotificationIcon>) NotificationIcon;

dictionary NotificationOptions {
    // ...
    NotificationIcon icon;
    // ...
};

The getter is interesting. It could just return whatever was passed in the dictionary (so either an USVString or the sequence), although it probably should be a FrozenArray?

Additionally, what's your thought on having a platform key? This is likely to be a bit controversial, but since most browsers defer to the platform notification systems which have wildly varying user interfaces, requirements and masking, it would provide developers with a much more convenient way to select an appropriate icon.

beverloo avatar Mar 10 '16 17:03 beverloo

If we are going to go object-oriented, sizes should be a sequence. If we're not, we should follow the example set by srcset, imo. Though I guess srcset is not really applicable since we don't care that much about layout here, just CSS pixels?

annevk avatar Mar 10 '16 17:03 annevk

What is a platform key?

annevk avatar Mar 10 '16 17:03 annevk

Operating system. windows, mac, android and so on. It won't be nice to specify, and we may want to shy away from having a normative list (MDN instead?), but it doesn't feel entirely inappropriate given that they are meant to be displayed in the platform's notification center.

beverloo avatar Mar 10 '16 17:03 beverloo

Oh I see, I would prefer to start out with something basic for v1. <link rel=icon> doesn't even have that feature.

annevk avatar Mar 10 '16 18:03 annevk

I'm not against punting, but the difference with <link rel=icon> is that our icons will be displayed in UI outside the browser's control. It does make sense to have that discussion separately.

beverloo avatar Mar 10 '16 18:03 beverloo

The concept of platform doesn't seem to fully address the problem. An OS has a theme and OS themes and OS versions do not have a 1:1 relationship. A theme can remain unchanged across multiple OS versions e.g. the Material theme on Android 5 and 6. On the other hand, one OS version may support multiple themes e.g. OSX Blue and Graphite. To further complicate things, a theme can evolve subtly across OS versions without being officially renamed.

Also, on Android, it is common for OEMs to apply their own themes (skins). And finally, in many OS’s the user can install additional themes or customize parts of it.

Defining this would be tricky, but I agree it would be helpful to have a reasonable solution. Perhaps something for a separate issue, @beverloo?

mvano avatar Mar 10 '16 18:03 mvano

It seems that srcset is bundled with a set of additional features we don't need, but that might not matter.

The width descriptor isn't quite a match for icons is it? It seems better to explicitly define width and height, even though most platforms expect square icons. Windows does not in all cases expect square images though. Aren't they all in pixels?

mvano avatar Mar 10 '16 18:03 mvano

I do prefer an object oriented approach. No big need to stick everything in a string for which we'd need to define parsing rules.

mvano avatar Mar 10 '16 18:03 mvano

Can sizes just be a sequence of integers representing raw pixels then? As in, [width1, height1, width2, height2, ...]. Not including sizes would be equivalent to <link rel=icon sizes>'s any. A list with a odd-numbered length would be invalid and treated like any.

annevk avatar Mar 11 '16 10:03 annevk

A sequence of (unsigned) integers would work, and be simple. A more detailed design could be to define a Size with width and height. Then I think we'd have something like this, summarizing the discussion so far:

dictionary NotificationIconSize {
  unsigned long width;
  unsigned long height;
};

dictionary NotificationIcon {
  USVString src;
  DOMString type;
  sequence<NotificationIconSize> sizes = [];
  double density;
};

typedef (USVString or sequence<NotificationIcon>) NotificationIcon;

dictionary NotificationOptions {
   NotificationIcon icon;
};

interface Notification {
  readonly attribute NotificationIcon icon;
};

Maybe we can typedef any into NotificationIconSize somehow?

mvano avatar Mar 11 '16 10:03 mvano

Wild suggestion: could some variation on HTTP Client Hints be used to get platform- and context-specific notification icons? (That is, there's just one URL in the source, but if the client passes along hints, and server can be bothered honoring them, it can deliver different images?)

(Whatever happen I hope authors will be able to avoid the favicon situation, where to do things right, pages get stuffed with multiple <link> and <meta> tags sprinkled with apple-touch-icon, icon, mask-icon, shortcut icon, msapplication-TileImage attributes, etc.)

ithinkihaveacat avatar Mar 11 '16 10:03 ithinkihaveacat

We could, I wonder if this is still convenient to use though. Why do you think size needs to be its own object? (Also, can Chrome these days easily return a JavaScript object from a getter?)

annevk avatar Mar 11 '16 10:03 annevk

@ithinkihaveacat we could do that too. I guess it depends on where you favor the complexity. Client Hints is also not something adopted by other browsers than Chrome yet and just yesterday some issues were raised against the specification (based on Mozilla dev.platform discussion).

annevk avatar Mar 11 '16 10:03 annevk

@annevk FrozenArray is still blocked, but hopefully we'll be able to use it in Q2. Sequences are fine, but they'll be values and not references (i.e. equality comparison fails).

Let's reserve the platform/theme discussion for another issue for when we agree on the basic approach. I think it's something we'll want to address, but Michael raises very good points.

@ithinkihaveacat I'm mostly ambivalent, but err towards a client-side preference to reduce the amount of necessary server-side logic. An ideal implementation would have cached images as part of the install event, which raises a question of which Client-Hints values to send— notifications may be displayed outside of the UA's control.

beverloo avatar Mar 11 '16 14:03 beverloo

@beverloo I was referring to the dictionary @mvano proposes to return from Notification instances. (And please don't introduce an attribute getter that keeps returning fresh instances anywhere. That's terrible. x.y === x.y should be true.)

annevk avatar Mar 11 '16 14:03 annevk

To be clear, I fully agree. We deliberately haven't yet shipped two getters (actions and vibrate) because of this.

beverloo avatar Mar 11 '16 14:03 beverloo

Simplifying the sizes syntax seems like a good idea as the common case would be to specify simply no or one size. Only .ico files contain multiples.

dictionary NotificationIcon {
  USVString src;
  DOMString type = "";
  sequence<unsigned long> sizes = [];
  double density = 1;
};

typedef (USVString or sequence<NotificationIcon>) NotificationIcons;

dictionary NotificationOptions {
   NotificationIcons icon;
};

interface Notification {
  readonly attribute NotificationIcons icon;
};

So common usage might look like this:

var Notification = new Notification('Title', {
    body: 'Some content',
    icon: [
      {src: 'icon_any.png'},
      {src: 'icon_64.png', sizes: [64, 64]},
      {src: 'icon_128.png', sizes: [128, 128]}
    ],
  }
);

I have a question about the typedef. The input should use a sequence, and the getter a FrozenArray, right? Then I don't think we can use the typedef this way.

mvano avatar Mar 16 '16 14:03 mvano

Yeah, you can't, unfortunately. I wonder if we can use [SameObject] for icon now it'll return an object sometimes.

annevk avatar Mar 16 '16 14:03 annevk