From 22579845a9ef6edbef2a3a71537824cbc14a70be Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Tue, 3 Nov 2015 18:42:36 +0200 Subject: [PATCH 1/5] Fix #66, #67, #68. Remove NFCAdapter. Simplify nfc namespace. Use the merged NFC adapter concept for multiple adapters. Update examples. --- index.html | 339 ++++++++++++++++++++++------------------------------- 1 file changed, 138 insertions(+), 201 deletions(-) diff --git a/index.html b/index.html index 9b93f1f..aa26a12 100644 --- a/index.html +++ b/index.html @@ -342,7 +342,7 @@ An NFC adapter is the software entity in the underlying platform which provides access to NFC functionality implemented in a given hardware element (NFC chip). A device may have multiple NFC - adapters, for instance a built-in one, and one attached via USB. + adapters, for instance a built-in one, and one or more attached via USB.

An NFC tag is a passive NFC device. @@ -608,20 +608,18 @@ this specification.

-    navigator.nfc.requestAdapter().then((adapter) => {
-      adapter.watch({}, (message) => {
-        console.log('NDEF message received from URL ' + message.url);
-        if (message[0].recordType == 'empty') {
-          adapter.pushMessage([
-            {
-              recordType: "text",
-              mediaType: "",
-              data: "Initializing tag"
-            }
-          ]);
-        }
-        processMessage(message);
-      });
+    navigator.nfc.watch({}, (message) => {
+      console.log('NDEF message received from URL ' + message.url);
+      if (message[0].recordType == 'empty') {
+        navigator.nfc.push([
+          {
+            recordType: "text",
+            mediaType: "",
+            data: "Initializing tag"
+          }
+        ]);
+      }
+      processMessage(message);
     });
 
     function processMessage(message) {
@@ -648,8 +646,7 @@
     };
   
-    navigator.nfc.requestAdapter().then((adapter) => {
-      adapter.pushMessage([
+    navigator.nfc.push([
         {
           recordType: "text",
           mediaType: "",
@@ -660,23 +657,18 @@
       }).catch(() => {
         console.log("Send failed :-( try again.");
       });
-    });
   
-    navigator.nfc.requestAdapter().then((adapter) => {
-      console.log("Awaiting game state");
-
-      adapter.watch({ url: "*://mydomain/mygame/*" }, (message) => {
-        console.log("Game state received from: " + message.url);
-        console.log("Stored state: " + message.data);
-
-        // Now do some calculations and then update the state.
-        // ...
-        adapter.pushMessage([ { data: { level: 3, points: 4500, lives: 3 }} ])
-        .then(() => { console.log('We have stored your current game state.'); })
-        .catch(() => { console.log('Failed updating game state, try again.'); });
-      });
+    navigator.nfc.watch({ url: "*://mydomain/mygame/*" }, (message) => {
+      console.log("Game state received from: " + message.url);
+      console.log("Stored state: " + message.data);
+
+      // Now do some calculations and then update the state.
+      // ...
+      navigator.nfc.push([ { data: { level: 3, points: 4500, lives: 3 }} ])
+      .then(() => { console.log('We have stored your current game state.'); })
+      .catch(() => { console.log('Failed updating game state, try again.'); });
     });
   
@@ -775,17 +767,22 @@ This use case is not supported in this version of the specification.

+

Support for multiple NFC adapters

+

+ Users may attach one or more external NFC adapters to their + devices, in addition to a built-in adapter. Users may use either + NFC adapter. +

+

Features

High level features for the Web NFC specification include the following:

  1. - Support devices with single or multiple NFC adapters. - If there are multiple adapters present when requesting an NFC adapter - then the UA MAY display a dialog for selecting one of them, - or MAY otherwise choose a default adapter based on user settings or - internal policy. + Support devices with single or multiple NFC adapters. + If there are multiple adapters present when invoking an NFC function + then the UA operates all NFC adapters in parallel.
  2. Support communication with active (powered devices such as readers, @@ -864,7 +861,8 @@

    Threats

    The main threats are summarized in the - Security and Privacy document. + + Security and Privacy document.

    In this specification the following threats are handled with the highest @@ -941,9 +939,9 @@ For details see the Writing or pushing content section.

  3. - When requesting an NFC adapter, or when setting up listeners for - reading, or when pushing NFC content, the UA may warn the user - that the given origin may be able to infer physical location. + When setting up NFC watches, when pushing NFC content, + the UA may warn the user that the given origin may be able to + infer physical location.
  4. Pushing Web NFC content to an NFC tag does not need to @@ -1224,17 +1222,31 @@

The NFC interface

- An NFC instance provides a way for the browsing context to - obtain an NFC adapter providing NFC functionality. - Implementations MAY expose multiple adapters. + The NFC object provides a way for the browsing context to + use NFC functionality. + It allows for pushing Web NFC messages to NFC tags + or NFC peers within range, and to set up and cancel NFC watches + to handle incoming Web NFC messages either from an NFC tag or an + NFC peer.
     interface NFC {
-      Promise<NFCAdapter> requestAdapter();
+      Promise<void> push(sequence<NFCRecord> message, NFCPushOptions options);
+      void cancelPush(NFCPushTarget target);
+      Promise<long> watch(NFCWatchOptions options, MessageCallback callback);
+      Promise<void> unwatch(long id);
     };
+
+    callback MessageCallback = void (NFCMessage message);
   
-

Internal slots of NFCAdapter

+

+ In later versions cancelPush() and unwatch() + may be obsoleted by + cancelable Promises used with push() and + watch(), respectively. +

+

Internal slots of NFC

- Instances of NFCAdapter are created with the internal slots + The NFC object is created with the internal slots described in the following table:

@@ -1248,8 +1260,9 @@ @@ -1262,86 +1275,24 @@
[[\suspended]] - A boolean flag indicating whether the adapter is suspended or not, - initially false. + A boolean flag indicating whether NFC functionality is + suspended or not, initially + false.
-

The requestAdapter() method

-

- The NFC.requestAdapter() method, when invoked MUST return a new - promise promise and run the following steps in parallel: -

    -
  1. - If the incumbent settings object is not a secure context, - reject promise with "SecurityError", - and abort these steps. -
    - Browsers may ignore this rule for development purposes only. -
    -
  2. -
  3. - If there is no support for NFC adapter handling functionality in - hardware, software, or due to physical incompatibility, - reject promise with - "NotSupportedError", and abort these steps. -
  4. -
  5. - Make a request to enumerate available NFC adapters. -
  6. -
  7. - If the request fails, reject promise with - "NotFoundError", and abort these steps. -
  8. -
  9. - Select one of the NFC adapters based on the following steps: -
      -
    1. Let adapter be null. -
    2. -
    3. - If there is only one NFC adapter, let adapter - denote that. -
    4. -
    5. - Otherwise, the UA MAY set adapter to a UA default or - allow the user to select one, for instance via a dialog. -
    6. -
    -
  10. -
  11. - If adapter is null, reject promise - with "NotFoundError", and abort these steps. -
  12. -
  13. - If there is any NFCAdapter instance - oldAdapter as a result of a previous invocation of this - algorithm, run the following sub-steps: -
      -
    1. - If oldAdapter is bound to adapter, resolve - promise with oldAdapter and terminate these - steps. -
    2. -
    3. - Otherwise run the NFC adapter release steps given - oldAdapter. -
    4. -
    -
  14. -
  15. - Resolve promise with a new NFCAdapter - object bound to adapter. -
  16. -
-

-
+

Handling NFC adapters

+ Implementations MAY use multiple NFC adapters + according to the algorithmic steps described in this specification. + + The NFC object represents all NFC hardware devices that can read and + write NFC content.

Handling Window visibility and focus

Each Window object connected to the - script execution environment has a separate - NFCAdapter instance. The + script execution environment has a separate NFC + instance. The visibility and focus state of the Window object determines the suspended state of the associated - NFCAdapter instance. + NFC instance.

The term suspended in this specification @@ -1349,7 +1300,7 @@ pushed, and no received NFC content is presented via watches while suspended. However, platform level timers for the - NFCAdapter.pushMessage() method continue running, + NFC.push() method continue running, and if they expire, the event should be recorded and handled when execution next resumes, i.e. when the focus event is fired on the Window object. @@ -1364,7 +1315,7 @@

  1. - Set NFCAdapter@[[\suspended]] to false. + Set NFC@[[\suspended]] to false.

@@ -1375,73 +1326,49 @@

  1. - Set NFCAdapter@[[\suspended]] to true. + Set NFC@[[\suspended]] to true.
-

Releasing NFCAdapter

+

Releasing NFC

If a user agent is to make disappear - an NFCAdapter object adapter, - run the following NFC adapter release steps, given - adapter: + an NFC object nfc, run the following + NFC release steps, given nfc:

-
    +
    1. - Set adapter@[[\suspended]] to true. + Set nfc@[[\suspended]] to true.
    2. - Run the adapter.cancelPush() + Run the nfc.cancelPush() steps with "tag" as parameter.
    3. - Run the adapter.cancelPush() + Run the nfc.cancelPush() steps with "peer" as parameter.
    4. Stop the dispatch NFC content steps.
    5. - Clear adapter@[[\watchList]]. + Clear nfc@[[\watchList]].
    6. - Release the NFC resources associated with adapter on the + Release the NFC resources associated with nfc on the underlying platform.

    - The UA should run the NFC adapter release steps, given - adapter, as additional steps to the + The UA should run the NFC release steps, given nfc, as + additional steps to the unloading document cleanup steps.

    -
-
+
-

The NFCAdapter interface

- The NFCAdapter represents an NFC hardware device which can read and - write data. It allows for pushing Web NFC messages to NFC tags - or NFC peers within range, and to set up and cancel NFC watches - to handle incoming Web NFC messages either from an NFC tag or an - NFC peer. -
-    interface NFCAdapter {
-      Promise<void> pushMessage(sequence<NFCRecord> message, NFCPushOptions options);
-      void cancelPush(NFCPushTarget target);
-      Promise<long> watch(NFCWatchOptions options, MessageCallback callback);
-      Promise<void> unwatch(long id);
-    };
-
-    callback MessageCallback = void (NFCMessage message);
-  
-

- In later versions cancelPush() and unwatch() - may be obsoleted by - cancelable Promises used with pushMessage() and - watch(), respectively. -

The NFCPushOptions dictionary

       enum NFCPushTarget {
@@ -1456,17 +1383,17 @@
     

The NFCPushOptions.target property - denotes the intended target for the pending pushMessage() + denotes the intended target for the pending push() operation.

The NFCPushOptions.timeout property - denotes the timeout for the pending pushMessage() + denotes the timeout for the pending push() operation expressed in milliseconds. The default value is implementation-dependent. The value Infinity means there is - no timeout. After the timeout expires, the - message set for pushing is cleared, an error is returned, and a new - Web NFC message can be set for pushing. + no timeout, i.e. no timer is started. After the timeout + expires, the message set for pushing is cleared, an error is returned, + and a new Web NFC message can be set for pushing.

The NFCWatchOptions dictionary

@@ -1550,10 +1477,10 @@ canceled by the cancelPush() method.

-

The pushMessage() method

-

+

The push() method

+

The - NFCAdapter.pushMessage(message, options) + NFC.push(message, options) method, when invoked, MUST run the push a message algorithm:

    @@ -1573,12 +1500,12 @@
  1. If there are any existing instance of this algorithm running - for the current NFC adapter whose target is equal - to options.target, abort that instance of this algorithm + whose target is equal to options.target, + abort that instance of this algorithm by rejecting its promise with "AbortError".

    - In other words, the current invocation of pushMessage() + In other words, the current invocation of push() rejects and replaces existing running invocations handling the same options.target. At any given moment there may be maximum two instances of this algorithm running: one targeting @@ -1666,18 +1593,34 @@

  2. Initiate data transfer to device using - output as buffer. -
  3. -
  4. - If the transfer is successful, resolve - promise and terminate these steps. + output as buffer, using the NFC adapter + in communication range with (connected to) + device.
  5. - Otherwise reject promise with + If the transfer fails, reject promise with "NetworkError" and terminate these steps. +

    + There is very small likelihood that a simultaneous tap + will happen on two or multiple different + NFC adapters. + If it happens, the user will likely need to repeat the + tap until full success. The error here gives an indication + that the operation needs to be repeated. Otherwise the + user may think the operation succeeded on all + NFC adapters. +

    +
  6. +
  7. + Clear output if no other NFC adapters are + using it for an ongoing transfer.
+
  • + When all ongoing transfers have finished, resolve + promise and terminate these steps. +
  • If this@[[\suspended]] is true, @@ -2128,12 +2071,12 @@

    -
    +

    The cancelPush method

    The - NFCAdapter.cancelPush(target) + NFC.cancelPush(target) method, when invoked, MUST run cancel push algorithm:

      @@ -2148,10 +2091,10 @@
    1. If the parameter target is "tag" and there is an instance of the - NFCAdapter.pushMessage() algorithm running with + NFC.push() algorithm running with options.target "tag", or if target is "peer" and there is an instance of - the NFCAdapter.pushMessage() algorithm running + the NFC.push() algorithm running with options.target "peer", then
      1. @@ -2182,7 +2125,7 @@

        Watching for content

        In order to receive NFC content, the client needs to call the - NFCAdapter.watch() to opt into content of interest. + NFC.watch() to opt into content of interest.

        Match patterns

        @@ -2244,7 +2187,7 @@

        An NFC watch is referring to a NFCWatchOptions filter saved together with the - NFCAdapter instance it belongs + NFC instance it belongs to, and a locally unique identifier which is used for cancellation. The section Receiving and parsing content uses NFC watches to match @@ -2254,12 +2197,9 @@ Multiple consecutive calls to the watch() method from the same origin create filters which are in OR relationship.

        -

        - Watch filters are grouped by NFC adapter. -

        When the - NFCAdapter.watch(options, callback) + NFC.watch(options, callback) method is invoked, the UA MUST run the following NFC watch algorithm:

          @@ -2294,9 +2234,8 @@ "SecurityError", and abort these steps.
        1. - If this is the first watch being set up for the current - NFC adapter, then make a request to listen to - NDEF messages. + If this is the first watch being set up, then make a request to + all NFC adapters to listen to NDEF messages.
        2. If the request fails, reject promise with @@ -2364,7 +2303,7 @@

          The unwatch() method

          - When the NFCAdapter.unwatch(id) method is + When the NFC.unwatch(id) method is invoked, the UA MUST return a Promise promise and run the following steps in parallel.

            @@ -2379,8 +2318,7 @@
          1. If the parameter id is undefined, then remove all watches and filters set by successive calls of the - NFC watch() method on the current - NFC adapter. + NFC watch() method on all NFC adapters.
          2. Otherwise, if the parameter id matches the local @@ -2392,9 +2330,8 @@ "NotFoundError", and abort these steps.
          3. - If there are no more watches on the current NFC adapter, - then make a request to stop listening to NDEF messages - on that adapter. + If there are no more watches, then make a request to stop listening + to NDEF messages on all NFC adapters.
          4. Resolve promise. @@ -2407,9 +2344,8 @@

            Receiving and parsing content

            - If there are any NFC watches set up for any NFC adapter in - their NFCAdapter@[[\watchList]], then - UAs MUST listen to NDEF messages, according to step 9 + If there are any NFC watches set up in NFC@[[\watchList]], + then UAs MUST listen to NDEF messages, according to step 9 of the NFC watch algorithm.

            The NDEF parsing algorithm

            @@ -2421,7 +2357,7 @@

            Receiving and parsing content

            1. - If NFCAdapter@[[\suspended]] is true, abort + If NFC@[[\suspended]] is true, abort these steps.
            2. @@ -2589,7 +2525,7 @@

              Receiving and parsing content

          5. - If NFCAdapter@[[\suspended]] is false and + If NFC@[[\suspended]] is false and message.data is not empty, run the dispatch NFC content steps given message.
          6. @@ -2646,7 +2582,8 @@

            Receiving and parsing content

        -
        +
    +

    Changes

    @@ -2664,7 +2601,7 @@

    Receiving and parsing content

  • Defined NFCMessage as a dictionary.
  • Improved definitions for URL and match pattern.
  • Added section for handling visibility and focus.
  • -
  • Added internal slots to NFCAdapter.
  • +
  • Added internal slots to NFC.
  • Changed push policy for background pages.
  • Changed receive policy for background pages.
  • Updated security policies and related algorithmic steps.
  • From 12b905dca6c4934689f73ceb9398b58858d61046 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Wed, 4 Nov 2015 10:06:21 +0200 Subject: [PATCH 2/5] Fix #69, #70, #73, #77, #80, #81, #82, #83, #84. Handle push related TAG review comments: simplified and aligned push message, optional push options with sensible defaults, improved push and cancelPush steps, option for suspending watches during push(), editorials. --- index.html | 224 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 129 insertions(+), 95 deletions(-) diff --git a/index.html b/index.html index aa26a12..a42ad3d 100644 --- a/index.html +++ b/index.html @@ -444,6 +444,8 @@

    The Web NFC message origin is an ASCII serialized origin with "https" scheme, stored in the Web NFC record. + For NFC content that is not a Web NFC message, it is + null.

    The Web NFC Id is a URL according to @@ -1229,9 +1231,11 @@ to handle incoming Web NFC messages either from an NFC tag or an NFC peer.

    +    typedef (DOMString or ArrayBuffer or NFCMessage) NFCPushMessage;
    +
         interface NFC {
    -      Promise<void> push(sequence<NFCRecord> message, NFCPushOptions options);
    -      void cancelPush(NFCPushTarget target);
    +      Promise<void> push(NFCPushMessage message, optional NFCPushOptions options);
    +      Promise<void> cancelPush(NFCPushTarget target);
           Promise<long> watch(NFCWatchOptions options, MessageCallback callback);
           Promise<void> unwatch(long id);
         };
    @@ -1281,6 +1285,7 @@
     
         The NFC object represents all NFC hardware devices that can read and
         write NFC content.
    +  

    Handling Window visibility and focus

    @@ -1373,12 +1378,14 @@

           enum NFCPushTarget {
             "tag",
    -        "peer"
    +        "peer",
    +        "any"
           };
     
           dictionary NFCPushOptions {
    -        NFCPushTarget target;
    -        unsigned long timeout;
    +        NFCPushTarget target = "any";
    +        unrestricted double timeout = Infinity;
    +        boolean ignoreRead = true;
           };
         

    @@ -1395,7 +1402,15 @@ expires, the message set for pushing is cleared, an error is returned, and a new Web NFC message can be set for pushing.

    +

    + The NFCPushOptions.ignoreRead property if true, + will make the push algorithm skip invoking the + receiving and parsing steps on the + read NFC content if the NFC device in communication range + is an NFC tag. +

    +

    The NFCWatchOptions dictionary

    To describe which messages an application is interested in, the @@ -1492,33 +1507,6 @@ If any exception occurs while running these steps, reject promise with that exception, and abort these steps. -

  • - If options.target is undefined, reject promise - with "SyntaxError", and abort these steps. - Otherwise let target be options.target, and - timeout be options.timeout. -
  • -
  • - If there are any existing instance of this algorithm running - whose target is equal to options.target, - abort that instance of this algorithm - by rejecting its promise with - "AbortError". -

    - In other words, the current invocation of push() - rejects and replaces existing running invocations handling the same - options.target. At any given moment there may be - maximum two instances of this algorithm running: one targeting - NFC tags, and another targeting NFC peers. -

    -

    - Implementations are expected to clean up state on aborting these - steps, e.g. stop the related timer, clear the related push - message, as well as release any resources bound to NFC - functionality, so that new invocations of this algorithm do not - depend on previous invocations. -

    -
  • If the incumbent settings object is not a secure context, reject promise with @@ -1539,18 +1527,27 @@
  • - If the obtain push permission steps given target - as parameter return false, then reject - promise with "SecurityError", and abort - these steps. + Let target be options.target or the default + "any".
  • - If the message parameter is an empty sequence, - then reject promise with "SyntaxError", - and abort these steps. + Let timeout be options.timeout or the + default Infinity. +
  • +
  • + If the message parameter is not of type + DOMString or ArrayBuffer or instance of + NFCPushMessage, reject promise with + "SyntaxError", and abort these steps.
  • - If options.timeout value is not valid or not supported + If the message parameter is instance of + NFCPushMessage, and message.data is an + empty sequence, reject promise with + "SyntaxError", and abort these steps. +
  • +
  • + If timeout value is not valid or it is not supported by the UA, reject promise with "SyntaxError", and abort these steps.
  • @@ -1562,9 +1559,41 @@ exception and abort these steps.
  • - If options.timeout value is not Infinity, + If target is "any", run the following + steps twice, once with slot with value + "tag", and once with the value "peer"; + otherwise run the following step once, with + slot given the value of target. +
  • +
      +
    • + If there are any existing instance of this algorithm running whose + target is equal to slot, abort that + instance of this algorithm by rejecting its promise + with "AbortError". +

      + In other words, the current invocation of push() + rejects and replaces existing running invocations handling the + same slot. At any given moment there may be + maximum two instances of this algorithm running: one targeting + NFC tags, and another targeting NFC peers. +

      +

      + Implementations are expected to clean up state on aborting these + steps, e.g. stop the related timer, clear the related push + message, as well as release any resources bound to NFC + functionality, so that new invocations of this algorithm do not + depend on previous invocations. +

      +
    • +
    • + Associate output with slot. +
    • +
    +
  • + If timeout value is not Infinity, start a timer timer with the timeout value set to - options.timeout. + timeout.
  • Wait until one of the following events happens: @@ -1575,22 +1604,43 @@
  • If the cancelPush() - method is called while timer is active, reject - promise with "AbortError", and + method is called while timer is active with + target or "any", then reject + promise with "AbortError" and terminate these steps, as described in the - cancelPush()algorithm. + cancelPush() steps.
  • - When an NFC device device comes within - communication range, and if this@[[\suspended]] is - false, and if device is an - NFC tag and target is "tag" or if - device is an NFC peer and target - is "peer", then + If an NFC device device comes within + communication range, which an NFC tag and + target is "tag" or "any", + or if device is an NFC peer and + target is "peer" or "any", + and this@[[\suspended]] is false, then + run the following sub-steps:
    1. Stop timer if active.
    2. +
    3. + If device is an NFC tag, + +
    4. Initiate data transfer to device using output as buffer, using the NFC adapter @@ -1603,24 +1653,21 @@ steps.

      There is very small likelihood that a simultaneous tap - will happen on two or multiple different + will happen on two or multiple different and connected NFC adapters. If it happens, the user will likely need to repeat the - tap until full success. The error here gives an indication - that the operation needs to be repeated. Otherwise the - user may think the operation succeeded on all - NFC adapters. + taps until full success, or one device at a time. + The error here gives an indication that the operation + needs to be repeated. Otherwise the user may think the + operation succeeded on all connected NFC adapters.

    5. - Clear output if no other NFC adapters are - using it for an ongoing transfer. + When the transfer has finished, clear output + associated with target, resolve + promise and terminate these steps.
    -
  • - When all ongoing transfers have finished, resolve - promise and terminate these steps. -
  • If this@[[\suspended]] is true, @@ -1635,32 +1682,14 @@

    Obtaining push permission

    - To obtain push permission given target of type - NFCPushTarget, run these steps: + To obtain push permission, run these steps:

    1. - If a prearranged trust relationship exists, - return true. -
    2. -
    3. - If target has the value "peer", + If there is a prearranged trust relationship, return true.
    4. - If target has the value "tag", read that - NFC tag. If it contains a Web NFC message with its - Web NFC message origin equal to the - ASCII serialized origin of the - incumbent settings object, then return true. -

      - In other words, updating NFC tags written by the same - origin does not require expressed permission. All - other writes, including that of empty tags, require - expressed permission. -

      -
    5. -
    6. - Optionally run the + Run the query permission status steps for the Web NFC permission name until completion. @@ -1676,9 +1705,11 @@
    7. Otherwise, if it resolved with - "prompt", then request permission from the user - for the Web NFC permission name. If that is granted, - return true. + "prompt", then optionally + + request permission from the user for the + Web NFC permission name. + If that is granted, return true.

      The @@ -1688,7 +1719,7 @@ origin and global object, store the result in the - permission store, and return the status. + permission store, and on success return true.

    8. @@ -2080,6 +2111,10 @@ method, when invoked, MUST run cancel push algorithm:

        +
      1. + Return a new Promise promise, and + then continue running this algorithm in parallel. +
      2. If the incumbent settings object is not a secure context, reject promise with @@ -2089,13 +2124,9 @@
      3. - If the parameter target is "tag" and - there is an instance of the - NFC.push() algorithm running with - options.target "tag", or if - target is "peer" and there is an instance of - the NFC.push() algorithm running - with options.target "peer", then + If there is an instance of the NFC.push() + algorithm running with its target equal to + target or "any", then
        1. Stop the instance's timer if it is active. @@ -2108,10 +2139,13 @@
        2. Reject the instance's pending promise with - "AbortError" and terminate the steps of the + "AbortError" and abort the steps of the instance.
        +
      4. + Resolve promise and terminate these steps. +

      From f06aa125e18830edea2747277e0aaa36669b0623 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Wed, 4 Nov 2015 10:59:01 +0200 Subject: [PATCH 3/5] Fix #71, #83, #85. Handle watch related TAG review comments: fix IDL for unwatch(), reverse param order for watch() and make options optional, make cancelPush target optional. --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index a42ad3d..616487c 100644 --- a/index.html +++ b/index.html @@ -1235,9 +1235,9 @@ interface NFC { Promise<void> push(NFCPushMessage message, optional NFCPushOptions options); - Promise<void> cancelPush(NFCPushTarget target); - Promise<long> watch(NFCWatchOptions options, MessageCallback callback); - Promise<void> unwatch(long id); + Promise<void> cancelPush(optional NFCPushTarget target="any"); + Promise<long> watch(MessageCallback callback, optional NFCWatchOptions options); + Promise<void> unwatch(optional long id); }; callback MessageCallback = void (NFCMessage message); From 4e85073c66a62ce4ffc8529eb00c394cd0f4398e Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Wed, 4 Nov 2015 18:29:08 +0200 Subject: [PATCH 4/5] Fix review comments, editorials. --- index.html | 131 ++++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 61 deletions(-) diff --git a/index.html b/index.html index 616487c..e47dbc6 100644 --- a/index.html +++ b/index.html @@ -1237,13 +1237,13 @@ Promise<void> push(NFCPushMessage message, optional NFCPushOptions options); Promise<void> cancelPush(optional NFCPushTarget target="any"); Promise<long> watch(MessageCallback callback, optional NFCWatchOptions options); - Promise<void> unwatch(optional long id); + Promise<void> cancelWatch(optional long id); }; callback MessageCallback = void (NFCMessage message);

      - In later versions cancelPush() and unwatch() + In later versions cancelPush() and cancelWatch() may be obsoleted by cancelable Promises used with push() and watch(), respectively. @@ -1403,11 +1403,10 @@ and a new Web NFC message can be set for pushing.

      - The NFCPushOptions.ignoreRead property if true, - will make the push algorithm skip invoking the - receiving and parsing steps on the - read NFC content if the NFC device in communication range - is an NFC tag. + When the value of the NFCPushOptions.ignoreRead property is + true, the push algorithm + will skip invoking the + receiving and parsing steps for an NFC tag.

    @@ -1505,19 +1504,19 @@
  • If any exception occurs while running these steps, reject - promise with that exception, and abort these steps. + promise with that exception and abort these steps.
  • If the incumbent settings object is not a secure context, reject promise with - "SecurityError", and abort these steps. + "SecurityError" and abort these steps.
    Browsers may ignore this rule for development purposes only.
  • An implementation MAY reject promise with - "NotSupportedError", and abort these steps. + "NotSupportedError" and abort these steps.
    The UA might terminate message push at this point. The reasons for terminations are implementation details. For example, the user @@ -1527,29 +1526,27 @@
  • - Let target be options.target or the default - "any". + Let target be options.target.
  • - Let timeout be options.timeout or the - default Infinity. + Let timeout be options.timeout.
  • - If the message parameter is not of type - DOMString or ArrayBuffer or instance of - NFCPushMessage, reject promise with - "SyntaxError", and abort these steps. + If the type of the message parameter is not + DOMString or ArrayBuffer, and it is not an + instance of NFCPushMessage, reject promise + with "SyntaxError", and abort these steps.
  • If the message parameter is instance of NFCPushMessage, and message.data is an empty sequence, reject promise with - "SyntaxError", and abort these steps. + "SyntaxError" and abort these steps.
  • If timeout value is not valid or it is not supported by the UA, reject promise with - "SyntaxError", and abort these steps. + "SyntaxError" and abort these steps.
  • Let output be the notation for the NDEF message @@ -1560,10 +1557,10 @@
  • If target is "any", run the following - steps twice, once with slot with value - "tag", and once with the value "peer"; + steps twice, once with slot set to the value + "tag", and once set to the value "peer"; otherwise run the following step once, with - slot given the value of target. + slot set to the value of target.
    • @@ -1591,7 +1588,7 @@
  • - If timeout value is not Infinity, + If timeout value is not equal to Infinity, start a timer timer with the timeout value set to timeout.
  • @@ -1607,17 +1604,27 @@ method is called while timer is active with target or "any", then reject promise with "AbortError" and - terminate these steps, as described in the + abort these steps, as described in the cancelPush() steps.
  • If an NFC device device comes within - communication range, which an NFC tag and - target is "tag" or "any", - or if device is an NFC peer and - target is "peer" or "any", - and this@[[\suspended]] is false, then - run the following sub-steps: + communication range, verify the following conditions: +
      +
    • + if device is an NFC tag, target + is "tag" or "any" +
    • +
    • + if device is an NFC peer, + target is "peer" or + "any" +
    • +
    • + this@[[\suspended]] is false. +
    • +
    + In case of success, run the following sub-steps:
    1. Stop timer if active. @@ -1627,17 +1634,18 @@
    2. @@ -1649,23 +1657,24 @@
    3. If the transfer fails, reject promise with - "NetworkError" and terminate these + "NetworkError" and abort these steps.

      + Multiple adapters should be used sequentially by users. There is very small likelihood that a simultaneous tap will happen on two or multiple different and connected NFC adapters. If it happens, the user will likely need to repeat the - taps until full success, or one device at a time. + taps until success, preferably one device at a time. The error here gives an indication that the operation needs to be repeated. Otherwise the user may think the operation succeeded on all connected NFC adapters.

    4. - When the transfer has finished, clear output + When the transfer has completed, clear output associated with target, resolve - promise and terminate these steps. + promise.
  • @@ -1772,7 +1781,7 @@
  • Otherwise reject promise with - "SyntaxError", and abort these steps. + "SyntaxError" and abort these steps.
  • @@ -1872,7 +1881,7 @@
    1. If record.data is not a string or number, - throw a "SyntaxError" exception, and abort these steps. + throw a "SyntaxError" exception and abort these steps.
    2. If record.mediaType is not a string or starts with @@ -1884,7 +1893,7 @@ for text. If not, then the UA MAY throw a "SyntaxError" - exception, and abort these steps. + exception and abort these steps.
    3. Let language be "en". @@ -1898,7 +1907,7 @@ in the IANA language registry (or [[ISO-639.2]]), then UAs MAY throw a "SyntaxError" - exception, and abort these steps. + exception and abort these steps.

      Note that lang= is not standard parameter @@ -2041,7 +2050,7 @@

    4. If record.data is not of instance of ArrayBuffer, reject promise with - "SyntaxError", and abort these steps. + "SyntaxError" and abort these steps.
    5. The UA MAY check if record.mediaType is @@ -2112,20 +2121,20 @@

      1. - Return a new Promise promise, and + Return a new Promise promise and then continue running this algorithm in parallel.
      2. If the incumbent settings object is not a secure context, reject promise with - "SecurityError", and abort these steps. + "SecurityError" and abort these steps.
        Browsers may ignore this rule for development purposes only.
      3. If there is an instance of the NFC.push() - algorithm running with its target equal to + algorithm running with its options.target equal to target or "any", then
        1. @@ -2144,7 +2153,7 @@
      4. - Resolve promise and terminate these steps. + Resolve promise.
      @@ -2246,12 +2255,12 @@
    6. If any exception occurs while running these steps, reject - promise with that exception, and abort these steps. + promise with that exception and abort these steps.
    7. If the incumbent settings object is not a secure context, reject promise with - "SecurityError", and abort these steps. + "SecurityError" and abort these steps.
      Browsers may ignore this rule for development purposes only.
      @@ -2259,13 +2268,13 @@
    8. If there is no support for the functionality of receiving data from an NFC peer or NFC tag in proximity range, reject - promise with "NotSupportedError", and - terminate this algorithm. + promise with "NotSupportedError" and + abort these steps.
    9. If the obtain watch permission steps return false, then reject promise with - "SecurityError", and abort these steps. + "SecurityError" and abort these steps.
    10. If this is the first watch being set up, then make a request to @@ -2273,7 +2282,7 @@
    11. If the request fails, reject promise with - "NotSupportedError" , and abort these steps. + "NotSupportedError" and abort these steps.
    12. Let watchId be a number that will identify this @@ -2334,17 +2343,17 @@

    - -

    The unwatch() method

    + +

    The cancelWatch() method

    - When the NFC.unwatch(id) method is + When the NFC.cancelWatch(id) method is invoked, the UA MUST return a Promise promise and run the following steps in parallel. -

      +
      1. If the incumbent settings object is not a secure context, reject promise with - "SecurityError", and abort these steps. + "SecurityError" and abort these steps.
        Browsers may ignore this rule for development purposes only.
        @@ -2361,7 +2370,7 @@
      2. Otherwise, reject promise with - "NotFoundError", and abort these steps. + "NotFoundError" and abort these steps.
      3. If there are no more watches, then make a request to stop listening @@ -2372,7 +2381,7 @@

      -
    +
    From a26764570e160a30583e0460195a058eb8f4d0f9 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Thu, 5 Nov 2015 17:08:11 +0200 Subject: [PATCH 5/5] Fix examples with the new spec. Add new examples. Add algorithm for Web NFC Id creation. --- index.html | 134 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 32 deletions(-) diff --git a/index.html b/index.html index e47dbc6..e784f2e 100644 --- a/index.html +++ b/index.html @@ -609,20 +609,55 @@ This section shows how developers can make use of the various features of this specification.

    +
    +    // Specifying an option for pushing to peers only,
    +    // and thus, do nothing when the user taps a tag.
    +    navigator.nfc.push("Text meant for peers only", { target: "peer" })
    +      .then(() => {
    +        console.log("Message pushed.");
    +      }).catch((error) => {
    +        console.log("Push failed :-( try again.");
    +      });
    +  
    +
    +    // Push a text string (here: serialized JSON), with no options specified
    +    // (target defaults to any device).
    +    navigator.nfc.push('{ prop1: "value1"; prop2: "value2" }')
    +      .then(() => {
    +        console.log("Message pushed.");
    +      }).catch((error) => {
    +        console.log("Push failed :-( try again.");
    +      });
    +  
    +
    +    // To push an NDEF record of URL type, use NFCMessage
    +    navigator.nfc.push({
    +        data: [{ recordType: "url", data: "/path/resource/" }];
    +      }).then(() => {
    +        console.log("Message pushed.");
    +      }).catch((error) => {
    +        console.log("Push failed :-( try again.");
    +      });
    +  
    -    navigator.nfc.watch({}, (message) => {
    +    // Use default options for watch.
    +    navigator.nfc.watch((message) => {
           console.log('NDEF message received from URL ' + message.url);
    -      if (message[0].recordType == 'empty') {
    -        navigator.nfc.push([
    -          {
    -            recordType: "text",
    -            mediaType: "",
    -            data: "Initializing tag"
    -          }
    -        ]);
    +      if (message.data[0].recordType == 'empty') {
    +        navigator.nfc.push({
    +          url: "/mypath/myapp",  // path set by the application
    +          data: [
    +            {
    +              recordType: "url",
    +              mediaType: "",  // this line could be omitted
    +              data: "Initial data"
    +            }
    +          ]});
           }
           processMessage(message);
    -    });
    +    }).then(() => { console.log("Watch added.");})
    +    .catch((error) => { console.log("Adding watch failed: " + error.name )});
     
         function processMessage(message) {
           message.data.forEach((record) => {
    @@ -647,31 +682,32 @@
           console.log('JSON data: ' + obj.myProperty.toString());
         };
       
    -
    -    navigator.nfc.push([
    -        {
    -          recordType: "text",
    -          mediaType: "",
    -          data: "Data meant for peers"
    -        }
    -      ]).then(() => {
    -        console.log("Message sent.");
    -      }).catch(() => {
    -        console.log("Send failed :-( try again.");
    -      });
    -  
    -    navigator.nfc.watch({ url: "*://mydomain/mygame/*" }, (message) => {
    +    // Watching for specific content; here only own game data.
    +    navigator.nfc.watch(reader, { url: "*/mypath/mygame/*" });
    +
    +    function reader(message) {
           console.log("Game state received from: " + message.url);
           console.log("Stored state: " + message.data);
     
           // Now do some calculations and then update the state.
    -      // ...
    -      navigator.nfc.push([ { data: { level: 3, points: 4500, lives: 3 }} ])
    +
    +      // Specify custom format, to control NDEF data layout.
    +      var message = {
    +        url: "https://company.com/path/game/update",  // app specific path
    +        data: [{
    +          recordType: "json",
    +          mediaType: "application/json",
    +          data: { level: 3, points: 4500, lives: 3 }
    +        }]
    +      };
    +
    +      // Push the message to tag or peer, whichever is tapped first.
    +      navigator.nfc.push(message)
           .then(() => { console.log('We have stored your current game state.'); })
    -      .catch(() => { console.log('Failed updating game state, try again.'); });
    -    });
    +      .catch((error) => { console.log('Failed updating game state, try again.'); });
    +    };
       
    @@ -1048,7 +1084,10 @@

    The NFCMessage.url - property represents the Web NFC Id of the Web NFC message. + property represents the Web NFC Id of a received + Web NFC message. When used in the NFC.push() + method, it represents a URL path used for constructing the + Web NFC Id of the pushed Web NFC content.

    The NFCMessage.data @@ -1827,7 +1866,9 @@

  • Let webnfc be the result of invoking - create a Web NFC record. + create a Web NFC record given message.url. + If this threw an exception, reject promise with that + exception and abort these steps.
  • Add webnfc to output. @@ -1885,7 +1926,7 @@
  • If record.mediaType is not a string or starts with - "text/", then throw a "SyntaxError" exception, + "text/", then throw a "SyntaxError" exception and abort these steps. In addition, UAs MAY check that @@ -2080,7 +2121,8 @@

    Creating a Web NFC record

    - To create a Web NFC record, run these steps: + To create a Web NFC record given url, + run these steps:

    1. Let ndef be the notation for the NDEF record to @@ -2093,6 +2135,11 @@ Set ndef.TYPE to "urn:nfc:ext:w3.org:webnfc".
    2. +
    3. + Let payload be the result of invoking + create a Web NFC Id given url. + If this threw an exception, re-throw it. +
    4. Set ndef.PAYLOAD to the URL path of the browsing context, encoded as UTF-16. @@ -2111,6 +2158,29 @@

    + +

    Creating a Web NFC Id

    +

    + To create a Web NFC Id given url, + run these steps: +

      +
    1. + Let id be the ASCII serialized origin of the + browsing context, appended with url. +
    2. +
    3. + If id is a not a valid URL, throw a + "SyntaxError" exception and abort these steps. +

      + This means url should be a valid URL path. +

      +
    4. +
    5. + Return id, encoded in UTF-16. +
    6. +
    +

    +
  • The cancelPush method