Merge
authortleithea
Wed, 08 Feb 2012 13:02:42 -0800
changeset 56 1964f4ceacde
parent 55 711a8502c132 (current diff)
parent 54 011c6e64df75 (diff)
child 57 03e88712c839
child 58 9e3ad7d9bd1b
Merge
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/battery/Overview.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,433 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Battery Status API</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+    <script src='http://respec.specifiction.com/js/profiles/w3c-common.js' class='remove'></script>
+    <script class="remove">
+      var respecConfig = {
+          specStatus:           "ED",
+          shortName:            "battery-status",
+          //publishDate:          "2011-11-29",
+          previousPublishDate:  "2011-11-29",
+          previousMaturity:     "LC",
+          edDraftURI:           "http://dvcs.w3.org/hg/dap/raw-file/tip/battery/Overview.html",
+          lcEnd:                "2011-12-20",
+          editors:  [
+              { name: "Anssi Kostiainen", company: "Nokia", companyURL: "http://nokia.com/" },
+              { name: "Mounir Lamouri", company: "Mozilla", companyURL: "http://mozilla.org/" }
+          ],
+          inlineCSS:    true,
+          noIDLIn:      true,
+          extraCSS:     ["../ReSpec.js/css/respec.css"],
+          wg:           "Device APIs Working Group",
+          wgURI:        "http://www.w3.org/2009/dap/",
+          wgPublicList: "public-device-apis",
+          wgPatentURI:  "http://www.w3.org/2004/01/pp-impl/43696/status",
+      };
+    </script>
+  </head>
+  <body>
+    <section id="abstract">
+      This specification defines an API that provides information about the
+      battery status of the hosting device.
+    </section>
+    
+    <section id="sotd">
+      <p>
+        The functionality described in this specification was initially
+        specified as part of the
+        <a href="http://www.w3.org/TR/system-info-api/">System Information
+        API</a> but has been extracted in order to be more readily available,
+        more straightforward to implement, and in order to produce a
+        specification that could be implemented on its own merits without
+        interference with other, often unrelated, features.
+      </p>
+    </section>
+    
+    <section class="informative">
+      <h2>Introduction</h2>
+      <p>
+        The Battery Status API specification defines a means for web
+        developers to programmatically determine the battery status of the
+        hosting device. Without knowing the battery status of a device, a web
+        developer must design the web application with an assumption of
+        sufficient battery level for the task at hand. This means the battery
+        of a device may exhaust faster than desired because web developers are
+        unable to make decisions based on the battery status. Given knowledge
+        of the battery status, web developers are able to craft web content and
+        applications which are power-efficient, thereby leading to improved
+        user experience.
+     </p>
+     <p>
+        The Battery Status API can be used to defer or scale back work when
+        the device is not charging in or is low on battery. An archetype of an
+        advanced web application, a web-based email client, may check the
+        server for new email every few seconds if the device is charging,
+        but do so less frequently if the device is not charging or is low on
+        battery. Another example is a web-based word processor which could
+        monitor the battery level and save changes before the battery runs
+        out to prevent data loss.
+      </p>
+      <p>
+        The following example shows how a web-based email client could check
+        for new emails every ten seconds without knowledge of the battery
+        status:
+      </p>
+      <pre class="example highlight">
+        &lt;!DOCTYPE html&gt;
+        &lt;html&gt;
+        &lt;head&gt;
+          &lt;title&gt;Email Client&lt;/title&gt;
+          &lt;script&gt;
+            var mail = {
+              INTERVAL_DEFAULT: 1000 * 10,
+              interval: null,
+              timer: 0,
+
+              check: function () {
+                console.log('Checking the server for new emails using an interval of ' + 
+                            (mail.interval / 1000) + ' seconds.');
+              },
+              
+              setTimer: function (interval) {
+                if (interval === mail.interval) { return; }
+                if (mail.timer !== 0) { clearTimeout(mail.timer); }
+                if (interval) { mail.timer = setInterval(function () { mail.check(); }, interval); }
+                mail.interval = interval;
+              }
+            };
+
+            window.addEventListener('load', function () {
+              mail.setTimer(!mail.interval ? mail.INTERVAL_DEFAULT : mail.interval);
+            }, false);
+          &lt;/script&gt;
+        &lt;/head&gt;
+        &lt;body&gt;&lt;/body&gt;
+        &lt;/html&gt;
+
+      </pre>
+      <p>
+        The script will always check for emails every ten seconds, even if the
+        battery level is critically low and the device is not charging.
+        This is an example of poor resource management.
+      </p>
+      <p>
+        Using the <a>BatteryManager</a> interface, the web application is, for
+        example, able to throttle checking for emails if the device is low on
+        battery, stop checking for emails if the battery is critically low and
+        resume normal operation when the battery is charging:
+      </p>
+      <pre class="example highlight">
+        &lt;!DOCTYPE html&gt;
+        &lt;html&gt;
+        &lt;head&gt;
+          &lt;title&gt;Battery-aware Email Client&lt;/title&gt;
+          &lt;script&gt;
+            var mail = {
+              INTERVAL_BATTERY_LOW: 1000 * 60 * 10,
+              INTERVAL_DEFAULT: 1000 * 10,
+              interval: null,
+              timer: 0,
+              
+              check: function () {
+                console.log('Checking the server for new emails using an interval of ' + 
+                            (mail.interval / 1000) + ' seconds.');
+              },
+              
+              setTimer: function (interval) {
+                if (interval === mail.interval) { return; }
+                if (mail.timer !== 0) { clearTimeout(mail.timer); }
+                if (interval) { mail.timer = setInterval(function () { mail.check(); }, interval); }
+                mail.interval = interval;
+              }
+            };
+            
+            window.addEventListener('load', function () {
+              mail.setTimer(!mail.interval ? mail.INTERVAL_DEFAULT : mail.interval);
+            }, false);
+            
+            var battery = navigator.battery;
+            
+            battery.addEventListener('dischargingtimechange', function () {
+              if (battery.dischargingTime &lt; 60 * 30 || battery.level &lt; 0.1) {
+                mail.setTimer(mail.INTERVAL_BATTERY_LOW);
+                console.log('30 minutes remaining or level below 10%, checking the server less frequently.');
+              } else if (battery.dischargingTime &lt; 60 * 10 || battery.level &lt; 0.05) {
+                mail.setTimer(null);
+                console.log('10 minutes remaining or level below 5%, stop checking the server.');
+              }
+            }, false);
+            
+            battery.addEventListener('chargingchange', function () {
+              if (battery.charging) {
+                mail.setTimer(mail.INTERVAL_DEFAULT);
+                console.log('Battery is charging, checking the server normally.');
+              }
+            }, false);
+          &lt;/script&gt;
+        &lt;/head&gt;
+        &lt;body&gt;&lt;/body&gt;
+        &lt;/html&gt;
+      </pre>
+    </section>
+    
+    <section id="conformance">
+      <p>
+        This specification defines conformance criteria that apply to a single
+        product: the <dfn>user agent</dfn> that implements the
+        interfaces that it contains.
+      </p>
+      <p>
+        Implementations that use ECMAScript to implement the APIs defined in
+        this specification must implement them in a manner consistent with the
+        ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]],
+        as this specification uses that specification and terminology.
+      </p>
+    </section>
+    <section>
+      <h2>Terminology</h2>
+      <p>
+        The <code><a href="http://dev.w3.org/html5/spec/webappapis.html#function">
+        Function</a></code> interface represents a function in the scripting
+        language being used as defined in [[!HTML5]].
+      </p>
+      <p>
+        The concepts <dfn><a href="http://dev.w3.org/html5/spec/webappapis.html#queue-a-task">
+        queue a task</a></dfn> and
+        <dfn><a href="http://dev.w3.org/html5/spec/webappapis.html#fire-a-simple-event">
+        fires a simple event</a></dfn> are defined in [[!HTML5]].
+      </p>
+      <p>
+        The terms <dfn> <a href="http://dev.w3.org/html5/spec/webappapis.html#event-handlers">
+        event handlers</a></dfn> and
+        <dfn><a href="http://dev.w3.org/html5/spec/webappapis.html#event-handler-event-type">
+        event handler event types</a></dfn> are defined in [[!HTML5]].
+      </p>
+    </section>
+    <section>
+      <h2>Security and privacy considerations</h2>
+      <p>
+        The API defined in this specification is used to determine the battery
+        status of the hosting device. The information disclosed has minimal
+        impact on privacy or fingerprinting, and therefore is exposed without
+        permission grants. For example, authors cannot directly know if there
+        is a battery or not in the hosting device.
+      </p>
+    </section>
+    <section>
+      <h2><a>NavigatorBattery</a> Interface</h2>
+      <p>
+        The <a>NavigatorBattery</a> interface is exposed on the 
+        <code>Navigator</code> object.
+      </p>
+      <div class="idl" title="Navigator implements NavigatorBattery"></div>
+      <dl title="[NoInterfaceObject] interface NavigatorBattery" class="idl">
+        <dt>readonly attribute BatteryManager battery</dt>
+        <dd>
+          The object that exposes the battery status information.
+        </dd>
+      </dl>
+    </section>
+    
+    <section>
+      <h2><a>BatteryManager</a> Interface</h2>
+      <dl title="[NoInterfaceObject]
+                 interface BatteryManager : EventTarget"
+          class="idl">
+        <dt>readonly attribute boolean charging</dt>
+        <dd>
+          Represents if the system's battery is charging. The attribute MUST be
+          set to false if the battery is discharging, and set to true, if the
+          battery is charging, the implementation is unable to report the
+          state, or there is no battery attached to the system, or otherwise.
+        </dd>
+        <dt>readonly attribute double chargingTime</dt>
+        <dd>
+          Represents the time remaining in seconds until the system's battery
+          is fully charged. The attribute MUST be set to 0, if the battery is
+          full or there is no battery attached to the system, and to the value
+          positive Infinity if the battery is discharging, the implementation
+          is unable to report the remaining charging time, or otherwise.
+        </dd>
+        <dt>readonly attribute double dischargingTime</dt>
+        <dd>
+          Represents the time remaining in seconds until the system's battery
+          is completely discharged and the system is about to be suspended. The
+          attribute MUST be set to the value positive Infinity, if the battery
+          is charging, the implementation is unable to report the remaining
+          discharging time, there is no battery attached to the system, or
+          otherwise.
+        </dd>
+        <dt>readonly attribute double level</dt>
+        <dd>
+          Represents the current battery level scaled from 0 to 1.0. The
+          attribute MUST be set to 0 if the system's battery is depleted and
+          the system is about to be suspended, and to 1.0 if the battery is
+          full, the implementation is unable to report the battery's level,
+          or there is no battery attached to the system.
+        </dd>
+        <dt>[TreatNonCallableAsNull] attribute Function? onchargingchange</dt>
+        <dd>
+        </dd>
+        <dt>[TreatNonCallableAsNull] attribute Function? onchargingtimechange</dt>
+        <dd>
+        </dd>
+        <dt>[TreatNonCallableAsNull] attribute Function? ondischargingtimechange</dt>
+        <dd>
+        </dd>
+        <dt>[TreatNonCallableAsNull] attribute Function? onlevelchange</dt>
+        <dd>
+        </dd>
+      </dl>
+      <p>
+        When a <code>BatteryManager</code> object is created,
+        <code>charging</code> MUST be set to true, <code>chargingTime</code>
+        to 0, <code>level</code> to 1.0 and <code>dischargingTime</code> to
+        the value positive Infinity, if the implementation is unable to report
+        the battery's charging state, charging time, level or remaining time
+        respectively.
+      </p>
+      <p>
+        When the battery charging state is updated, the <a>user agent</a> MUST
+        <a>queue a task</a> which sets the <code>charging</code> attribute's
+        value and <a>fires a simple event</a> named <code>chargingchange</code>
+        at the <a>BatteryManager</a> object.
+      </p>
+      <p>
+        When the battery charging time is updated, the <a>user agent</a> MUST
+        <a>queue a task</a> which sets the <code>chargingTime</code>
+        attribute's value and <a>fires a simple event</a> named
+        <code>chargingtimechange</code> at the <a>BatteryManager</a> object.
+      </p>
+      <p>
+        When the battery discharging time is updated, the <a>user agent</a>
+        MUST <a>queue a task</a> which sets the <code> dischargingTime</code>
+        attribute's value and <a>fires a simple event </a> named
+        <code>dischargingtimechange</code> at the <a>BatteryManager</a> object.
+      </p>
+      <p>
+        When the battery level is updated, the <a>user agent</a> MUST
+        <a>queue a task</a> which sets the <code> level</code> attribute's
+        value and <a>fires a simple event</a> named <code>levelchange</code>
+        at the <a>BatteryManager</a> object.
+      </p>
+      <div class="note">
+        The definition of how often the <code>chargingtimechange</code>,
+        <code>dischargingtimechange</code>, and <code>levelchange</code> events
+        are fired is left to the implementation.
+      </div>
+      <section>
+        <h2>Event handlers</h2>
+        <p>
+          The following are the <a>event handlers</a> (and their corresponding
+          <a>event handler event types</a>) that MUST be supported as
+          attributes by the <a>BatteryManager</a> object:
+        </p>
+        <table class="simple">
+          <thead>
+            <tr>
+              <th>event handler</th>
+              <th>event handler event type</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td><strong><code>onchargingchange</code></strong></td>
+              <td><code>chargingchange</code></td>
+            </tr>
+            <tr>
+              <td><strong><code>onchargingtimechange</code></strong></td>
+              <td><code>chargingtimechange</code></td>
+            </tr>
+            <tr>
+              <td><strong><code>ondischargingchange</code></strong></td>
+              <td><code>dischargingchange</code></td>
+            </tr>
+            <tr>
+              <td><strong><code>onlevelchange</code></strong></td>
+              <td><code>levelchange</code></td>
+            </tr>
+          </tbody>
+        </table>
+      </section>
+    </section>
+
+    <section class="informative">
+      <h2>Examples</h2>
+      <p>
+        This trivial example writes the battery level to the console each time
+        the level changes:
+      </p>
+      <div class="example">
+        <pre class="example highlight">
+          navigator.battery.onlevelchange = function () {
+            console.log(navigator.battery.level);
+          };
+        </pre>
+      </div>
+      <p>
+        Alternatively, the same using the <code>addEventListener()</code>
+        method:
+      </p>
+      <div class="example">
+        <pre class="example highlight">
+        navigator.battery.addEventListener('levelchange', function () {
+          console.log(navigator.battery.level);
+        }, false);
+        </pre>
+      </div>
+      <p>
+        The following example updates the indicators to show the charging
+        state, level and time remaining in minutes:
+      </p>
+      <div class="example">
+        <pre class="example highlight">
+          &lt;!DOCTYPE html&gt;
+          &lt;html&gt;
+          &lt;head&gt;
+            &lt;title&gt;Battery Status API Example&lt;/title&gt;
+            &lt;script&gt;
+              var battery = navigator.battery;
+              
+              battery.onchargingchange = function () {
+                document.querySelector('#charging').textContent = battery.charging ? 'charging' : 'not charging';
+              };
+
+              battery.onlevelchange = function () {
+                document.querySelector('#level').textContent = battery.level;
+              };
+
+              battery.ondischargingtimechange = function () {
+                document.querySelector('#dischargingTime').textContent = battery.dischargingTime / 60;
+              };
+            &lt;/script&gt;
+          &lt;/head&gt;
+          &lt;body&gt;
+            &lt;div id="charging"&gt;(charging state unknown)&lt;/div&gt;
+            &lt;div id="level"&gt;(battery level unknown)&lt;/div&gt;
+            &lt;div id="dischargingTime"&gt;(discharging time unknown)&lt;/div&gt;
+          &lt;/body&gt;
+          &lt;/html&gt;
+        </pre>
+      </div>
+    </section>
+    <section class="appendix">
+      <h2>Acknowledgements</h2>
+      <p>
+        The group is deeply indebted to Mounir Lamouri, Jonas Sicking, and
+        the Mozilla WebAPI team in general for their invaluable feedback
+        based on prototype implementations. Many thanks to the people behind
+        the System Information API and Device Orientation Event specification
+        for the initial inspiration. Also thanks to the nice folks bringing us
+        the Page Visibility specification, which motivated the editor of this
+        specification to write the introduction chapter discussing some
+        real-world high value use cases that apply equally to this
+        specification. Special thanks to all the participants of the Device
+        APIs Working Group and others who have sent in substantial feedback
+        and comments, and made the Web a better place for everyone by
+        doing so.
+      </p>
+    </section>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/battery/index.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Battery Status API</title>
+  </head>
+  <body>
+    Moved to <a href="http://dvcs.w3.org/hg/dap/raw-file/tip/battery/Overview.html">
+    http://dvcs.w3.org/hg/dap/raw-file/tip/battery/Overview.html</a>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/network-api/index.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,307 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>The Network Information API</title>
+    <meta http-equiv='Content-Type' content='text/html;charset=utf-8' />
+
+<!--
+    <script src='../ReSpec.js/js/respec.js' class='remove'></script>
+-->
+    <script src='http://respec.specifiction.com/js/profiles/w3c-common.js' class='remove'></script>
+    <script class='remove'>
+      var respecConfig = {
+          specStatus:           "ED",
+          shortName:            "netinfo-api",
+
+          //publishDate:  "2012-12-12",
+          previousPublishDate:  "2011-06-07",
+          previousMaturity:     "ED",
+          edDraftURI:           "TBD",
+
+          // if this is a LCWD, uncomment and set the end of its review period
+          // lcEnd: "2009-08-05",
+          extraCSS:             ["../ReSpec.js/css/respec.css"],
+          noIDLIn:    true,
+
+          editors:  [
+              { name: "Mounir Lamouri",
+                company: "Mozilla",
+                companyURL: "http://mozilla.org/" },
+          ],
+          wg:           "Device APIs and Policy Working Group",
+          wgURI:        "http://www.w3.org/2009/dap/",
+          wgPublicList: "public-device-apis",
+          wgPatentURI: "http://www.w3.org/2004/01/pp-impl/43696/status"
+      };
+    </script>
+  </head>
+
+  <body>
+    <section id='abstract'>
+      The Network Information API provides an interface for web applications to
+      access the underlying connection information of the device.
+    </section>
+
+    <section id='sotd'>
+      <p>
+        The functionality described in this specification was initially specified as part of the
+        <a href='http://www.w3.org/TR/system-info-api/'>System Information API</a> but has been
+        extracted in order to be more readily available, more straightforward to implement, and
+        in order to produce a specification that could be implemented on its own merits without
+        interference with other, often unrelated, features.
+      </p>
+    </section>
+
+    <section class="informative">
+      <h2>Introduction</h2>
+      <p>
+        The Network Information API provides an interface enabling web applications to access the underlying
+        connection information of the device.
+      </p>
+      <p>
+        The following example shows how an image viewer can select a low definition or a high definition image based on the
+        current connection bandwidth:
+      <pre class="example highlight">
+        &lt;!DOCTYPE&gt;
+        &lt;html&gt;
+          &lt;head&gt;
+            &lt;title&gt;Poney viewer&lt;/title&gt;
+          &lt;/head&gt;
+          &lt;body&gt;
+            &lt;img id='poney' alt="An image showing a poney" title="My precious!"&gt;
+            &lt;script&gt;
+              var i = document.getElementById('poney');
+
+              if (navigator.connection.bandwidth > 2) {
+                i.src = "http://example.com/poney_hd.png";
+              } else {
+                i.src = "http://example.com/poney_ld.png";
+              }
+            &lt;/script&gt;
+          &lt;/body&gt;
+        &lt;/html&gt;
+      </pre>
+    </section>
+
+    <section id='conformance'>
+      <p>
+        This specification defines conformance criteria that apply to a single product: the <dfn>user agent</dfn> that
+        implements the interfaces that it contains.
+      </p>
+      <p>
+        Implementations that use ECMAScript to expose the APIs defined in this specification must implement them in a manner
+        consistent with the ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]].
+      </p>
+    </section>
+
+    <section>
+      <h2>Terminology</h2>
+      <p>
+        The <code><a href="http://dev.w3.org/html5/spec/webappapis.html#function">
+        Function</a></code> interface represents a function in the scripting
+        language being used as defined in [[!HTML5]].
+      </p>
+      <p>
+        The concepts <dfn><a href="http://dev.w3.org/html5/spec/webappapis.html#queue-a-task">
+        queue a task</a></dfn> and
+        <dfn><a href="http://dev.w3.org/html5/spec/webappapis.html#fire-a-simple-event">
+        fire a simple event</a></dfn> are defined in [[!HTML5]].
+      </p>
+
+      <p>
+        The terms <dfn> <a href="http://dev.w3.org/html5/spec/webappapis.html#event-handlers">
+        event handlers</a></dfn> and
+        <dfn><a href="http://dev.w3.org/html5/spec/webappapis.html#event-handler-event-type">
+        event handler event types</a></dfn> are defined in [[!HTML5]].
+      </p>
+
+      <p>
+        The concepts of <dfn><a href="http://dev.w3.org/html5/spec/browsers.html#browsing-context">
+        browsing context</a></dfn> and
+        <dfn><a href="http://dev.w3.org/html5/spec/browsers.html#active-document">
+        active document</a></dfn> are defined in [[!HTML5]].
+      </p>
+
+      <p>
+        The concept of document <dfn><a href="http://dev.w3.org/html5/spec/origin-0.html#the-document-s-domain">
+        domain</a></dfn> is defined in [[!HTML5]].
+      </p>
+    </section>
+
+    <section>
+      <h2>Security and privacy considerations</h2>
+      <p>
+        The API defined in this specification is used to determine the connection information
+        of the hosting device. The information disclosed has minimal
+        impact on privacy or fingerprinting, and therefore is exposed without
+        permission grants. For example, authors cannot directly know what kind of connection
+        is actually in use by the hosting device.
+      </p>
+    </section>
+
+    <section>
+      <h2>The <a>NetworkInformation</a> interface</h2>
+      <p>
+        The <a>NetworkInformation</a> interface is exposed on the 
+        <code>Navigator</code> object.
+      </p>
+      <div class='idl' title='Navigator implements NetworkInformation'></div>
+      <dl title='[NoInterfaceObject] interface NetworkInformation' class='idl'>
+        <dt>readonly attribute Connection connection</dt>
+        <dd>
+          The object from which connection information is accessed.
+        </dd>
+      </dl>
+    </section>
+
+    <section>
+      <h2>The <a>Connection</a> interface</h2>
+      <p>
+        The <a>Connection</a> interface provides a handle to the device's connection information.
+      </p>
+      <dl title='[NoInterfaceObject]
+                 interface Connection : EventTarget' class='idl'>
+        <dt>readonly attribute double  bandwidth</dt>
+        <dd>
+          The <a>user agent</a> MUST set the value of the <code>bandwidth</code> attribute to:
+          <ul>
+            <li>0 if the user is currently offline;</li>
+            <li>Infinity if the bandwidth is unknown;</li>
+            <li>an estimation of the current bandwidth in MB/s (Megabytes per seconds) available for communication with the
+                <a>browsing context</a> <a>active document</a>'s <a>domain</a>.
+            </li>
+          </ul>
+        </dd>
+        <dt>readonly attribute boolean metered</dt>
+        <dd>
+          <p>
+            A connection is <dfn>metered</dfn> when the user's connection is subject to a limitation from his Internet Service Provider
+            strong enough to request web applications to be careful with the bandwidth usage.
+          </p>
+          <div class="note">
+            What is a metered connection is voluntarily left to the <a>user agent</a> to judge. It would not be possible to give an exhaustive
+            list of limitations considered strong enough to flag the connection as metered and even if doable, some limitations can be
+            considered strong or weak depending on the context.<br>
+            Examples of metered connections are mobile connections with a small bandwidth quota or connections with a pay-per use plan.
+          </div>
+          <p>
+            The <a>user agent</a> MUST set the value of the <code>metered</code> attribute to true if the connection with the
+            <a>browsing context</a> <a>active document</a>'s <a>domain</a> is <a title='metered'>metered</a> and false otherwise.
+            If the implementation is not able to know the status of the connection or if the user is offline, the value MUST be set to false.
+          </p>
+          <div class="note">
+            If unnable to know if a connection is metered, a <a>user agent</a> could ask the user about the status of his current connection.
+            For example, a preference could let the user define if the mobile connection used on the device is metered.
+          </div>
+        </dd>
+        <dt>[TreatNonCallableAsNull] attribute Function? onchange</dt>
+        <dd></dd>
+      </dl>
+
+      <p>
+        When the <code>Connection</code> changes, the <a>user agent</a> MUST <a>queue a task</a> which updates
+        the <code>Connection</code> properties and <a>fire a simple event</a> named <code>change</code> at the
+        <code>Connection</code> object.
+      </p>
+
+      <p>
+        When the user goes online or offline, in addition to the <code>change</code> event fired on the <code>Connection</code>
+        object, the <a>user agent</a> has to <a>fire a simple event</a> named either <code>online</code> or <code>offline</code>
+        depending on the applicable value, as defined in [[!HTML5]].
+      </p>
+
+      <section>
+        <h2>Event handlers</h2>
+        <p>
+          The following are the <a>event handlers</a> (and their corresponding
+          <a>event handler event types</a>) that MUST be supported as
+          attributes by the <code>Connection</code> object:
+        </p>
+
+        <table class="simple">
+          <thead>
+            <tr>
+              <th>event handler</th>
+              <th>event handler event type</th>
+            </tr>
+          </thead>
+          <tbody>
+
+            <tr>
+              <td><strong><code>onchange</code></strong></td>
+              <td><code>change</code></td>
+            </tr>
+          </tbody>
+        </table>
+      </section>
+    </section>
+
+    <section class='informative'>
+      <h2>Examples</h2>
+      <p>
+        This trivial example writes the connection bandwidth to the console and shows it again each time it is changing:
+      </p>
+      <div class="example">
+        <pre class="example highlight">
+          function show() {
+            console.log(navigator.connection.bandwidth);
+          }
+
+          navigator.connection.addEventListener('change', show, false);
+
+          show();
+        </pre>
+      </div>
+
+      <p>
+        This example shows how an application can prevent automatic polling using the metered attribute:
+      </p>
+      <div class="example">
+        <pre class="example highlight">
+          &lt;!DOCTYPE html&gt;
+          &lt;html&gt;
+            &lt;head&gt;
+              &lt;title&gt;Conditional polling&lt;/title&gt;
+              &lt;script&gt;
+                var gPreviousMetered = navigator.connection.metered;
+                var gIntervalId;
+
+                function poll() {
+                  // poll stuff
+                }
+
+                navigator.connection.addEventListener('change', function() {
+                  if (gPreviousMetered == navigator.connection.metered) {
+                    return;
+                  }
+
+                  gPreviousMetered = navigator.connection.metered;
+                  if (navigator.connection.metered) {
+                    gIntervalId = setInterval(poll, 1000);
+                  } else {
+                    clearInterval(gIntervalId);
+                  }
+                }, false);
+
+                // At load time.
+                if (!navigator.connection.metered) {
+                  gIntervalId = setInterval(poll, 1000);
+                }
+              &lt;/script&gt;
+            &lt;/head&gt;
+            &lt;body&gt;
+              &lt;button onclick="poll();"&gt;Poll&lt;/button&gt;
+            &lt;/body&gt;
+          &lt;/html&gt;
+        </pre>
+      </div>
+    </section>
+
+    <section class='appendix'>
+      <h2>Acknowledgements</h2>
+      <p>
+        Special thanks to Robin Berjon for his help.
+      </p>
+    </section>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/TODO.txt	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,29 @@
+
+TESTS:
+    ✓ API presence
+    ✓ silent ignore (requires a device that does not support vibration)
+    ✓ simple value
+    ✓ array of values
+    ✓ array with extra parameter (even array)
+    ✓ cancel with 0
+    ✓ cancel with []
+    ✓ cancel with new vibration
+    - do nothing when hidden
+    - cancel when dynamically hidden
+    - reinstate when dynamically shown
+
+
+NOTES:
+• Test using vendor prefix as in
+ http://dvcs.w3.org/hg/webperf/file/25712d0f6bd5/tests/submission/Microsoft/PageVisibility/support/featuredetection.js
+
+• Testing transitions as in
+http://dvcs.w3.org/hg/webperf/file/25712d0f6bd5/tests/submission/Microsoft/PageVisibility/test_tab_switch.htm
+
+• When the visibilitychange event [PAGE-VISIBILITY] is dispatched at the Document, the user agent must run the following steps
+    - If the hidden attribute [PAGE-VISIBILITY] is set to true, the user agent must 
+      suppress the vibration produced by running the pre-existing instance of the processing 
+      vibration patterns algorithm, if any.
+    - If the hidden attribute [PAGE-VISIBILITY] is set to false, the user agent must 
+      restore the vibration produced by running the pre-existing instance of the 
+      processing vibration patterns algorithm, if any.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/api-is-present.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: test that the vibrate() method is present (with or without vendor prefix)</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom'/>
+    <meta name='assert' content='Check that the vibrate() method is present.'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      This test checks for the presence of the <code>vibrate()</code> method, taking
+      vendor prefixes into account.
+    </p>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script>
+      test(function () {
+          assert_true(undefined !== BrowserHasFeature(navigator, "vibrate"), "navigator.vibrate exists");
+      }, "vibrate() is present on navigator");
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/cancel-with-0.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: cancel ongoing vibrate() with 0</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, interact'/>
+    <meta name='assert' content='If pattern is 0, cancel the pre-existing instance of the processing vibration patterns algorithm'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      After hitting the button below, your device must vibrate for a short period of time (roughly one
+      second). If it vibrates for a longer time (roughly five seconds, it should feel somewhat long) then
+      the test has failed.
+    </p>
+    <button id='vib'>Vibrate!</button>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          document.getElementById("vib").onclick = function () {
+              navigator.vibrate(5000);
+              setTimeout(function () {
+                  navigator.vibrate(0);
+              }, 1000);
+          };
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/cancel-with-[].html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: cancel ongoing vibrate() with []</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, interact'/>
+    <meta name='assert' content='If pattern is an empty list, cancel the pre-existing instance of the processing vibration patterns algorithm'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      After hitting the button below, your device must vibrate for a short period of time (roughly one
+      second). If it vibrates for a longer time (roughly five seconds, it should feel somewhat long) then
+      the test has failed.
+    </p>
+    <button id='vib'>Vibrate!</button>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          document.getElementById("vib").onclick = function () {
+              navigator.vibrate(5000);
+              setTimeout(function () {
+                  navigator.vibrate([]);
+              }, 1000);
+          };
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/cancel-with-new.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: cancel ongoing vibrate() with a new call to vibrate</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, interact'/>
+    <meta name='assert' content='Cancel the pre-existing instance of the processing vibration patterns algorithm, if any.'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      After hitting the button below, your device must vibrate continuously for a short period of time (roughly one
+      second), then vibrate a series of short bursts. If the initial continuously vibration is longer (roughly five
+      seconds, it should feel somewhat long) or if there is no series of short vibration bursts then the test has
+      failed.
+    </p>
+    <button id='vib'>Vibrate!</button>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          document.getElementById("vib").onclick = function () {
+              navigator.vibrate(5000);
+              setTimeout(function () {
+                  navigator.vibrate([200, 200, 200, 200, 200, 200, 200, 200, 200]);
+              }, 1000);
+          };
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/manifest.txt	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,9 @@
+api-is-present.html		Vibration API: test that the vibrate() method is present (with or without vendor prefix)	vendor-prefix, dom	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	Check that the vibrate() method is present.
+cancel-with-0.html		Vibration API: cancel ongoing vibrate() with 0	vendor-prefix, dom, interact	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	If pattern is 0, cancel the pre-existing instance of the processing vibration patterns algorithm
+cancel-with-[].html		Vibration API: cancel ongoing vibrate() with []	vendor-prefix, dom, interact	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	If pattern is an empty list, cancel the pre-existing instance of the processing vibration patterns algorithm
+cancel-with-new.html		Vibration API: cancel ongoing vibrate() with a new call to vibrate	vendor-prefix, dom, interact	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	Cancel the pre-existing instance of the processing vibration patterns algorithm, if any.
+pattern-array-extra.html		Vibration API: test a pattern array parameter to vibrate() with an extra (even) item	vendor-prefix, dom, interact	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	If the length of pattern is even, then remove the last entry in pattern.
+pattern-array.html		Vibration API: test a pattern array parameter to vibrate()	vendor-prefix, dom, interact	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	
+silent-ignore.html		Vibration API: test that calls to vibrate() are silently ignored when the device cannot vibrate	vendor-prefix, dom, no-vibrator	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	If the device does not provide a vibration mechanism, or it is disabled, the user agent must silently ignore any invocations of the vibrate() method.
+simple-array.html		Vibration API: test a simple array parameter to vibrate()	vendor-prefix, dom, interact	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	
+simple-scalar.html		Vibration API: test a simple scalar parameter to vibrate()	vendor-prefix, dom, interact	http://www.w3.org/TR/vibration/#methods		Robin Berjon <mailto:robin@berjon.com>	
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/pattern-array-extra.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: test a pattern array parameter to vibrate() with an extra (even) item</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, interact'/>
+    <meta name='assert' content='If the length of pattern is even, then remove the last entry in pattern.'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      After hitting the button below, your device must vibrate three times for one second, separated
+      by one second intervals.
+    </p>
+    <button id='vib'>Vibrate!</button>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          document.getElementById("vib").onclick = function () {
+              navigator.vibrate([1000, 1000, 1000, 1000, 1000, 1000]);
+          };
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/pattern-array.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: test a pattern array parameter to vibrate()</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, interact'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      After hitting the button below, your device must vibrate three times for one second, separated
+      by one second intervals.
+    </p>
+    <button id='vib'>Vibrate!</button>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          document.getElementById("vib").onclick = function () {
+              navigator.vibrate([1000, 1000, 1000, 1000, 1000]);
+          };
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/silent-ignore.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: test that calls to vibrate() are silently ignored when the device cannot vibrate</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, no-vibrator'/>
+    <meta name='assert' content='If the device does not provide a vibration mechanism, or it is disabled, the user agent must silently ignore any invocations of the vibrate() method.'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      <strong>This test is only useful on devices that do not have vibration capability</strong>.
+      If your device supports vibration, then <strong>skip</strong> this test. An implementation
+      supporting this API but running on a device that cannot vibrate must silently ignore the
+      call (we test that it doesn't throw).
+    </p>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          test(function () {
+              var ok = false;
+              try {
+                  navigator.vibrate(1000);
+                  ok = true;
+              }
+              catch (e) {
+                  ok = false;
+              }
+              assert_true(ok, "vibrate() should not throw");
+          }, "Calling vibrate does not throw.");
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/simple-array.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: test a simple array parameter to vibrate()</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, interact'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      After hitting the button below, your device must vibrate continuously for about two seconds, once.
+    </p>
+    <button id='vib'>Vibrate!</button>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          document.getElementById("vib").onclick = function () {
+              navigator.vibrate([2000]);
+          };
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/submissions/robin/simple-scalar.html	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' lang='en'>
+  <head>
+    <meta charset='utf-8'/>
+    <title>Vibration API: test a simple scalar parameter to vibrate()</title>
+    <link rel='author' title='Robin Berjon' href='mailto:robin@berjon.com'/>
+    <link rel='help' href='http://www.w3.org/TR/vibration/#methods'/>
+    <meta name='flags' content='vendor-prefix, dom, interact'/>
+    <!-- 
+      When you review this test, please add
+      <link rel='reviewer' title='Your Name' href='mailto:your-email-address'/>
+    -->
+    <link rel='stylesheet' href='http://w3c-test.org/resources/testharness.css' media='all'/>
+  </head>
+  <body>
+    <h1>Description</h1>
+    <p>
+      After hitting the button below, your device must vibrate continuously for about two seconds, once.
+    </p>
+    <button id='vib'>Vibrate!</button>
+    <div id='log'></div>
+    <script src='http://w3c-test.org/resources/testharness.js'></script>
+    <!-- When this test gets approved, remove a "../" below -->
+    <script src='../../support/feature-detection.js'></script>
+    <script src='../../support/helpers.js'></script>
+    <script>
+      if (supportsVibration()) {
+          document.getElementById("vib").onclick = function () {
+              navigator.vibrate(2000);
+          };
+      }
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/support/feature-detection.js	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,94 @@
+
+// 2012-01-27
+//  The code below has been stolen from Microsoft's submission tests to the Page Visibility
+//  specification. Thanks!
+
+
+// This function returns the value of an API feature if it is defined with one of
+// the known ventor prefixes. 
+//
+// Parameters:
+//  parent: the object containing the API feature
+//  feature: the name of the API feature, this should be a string value
+//  isAttribute: set this to true to indicate that this is a constant attribute
+//               as opposed to a variable
+function BrowserHasFeature(parent, feature, isAttribute)
+{
+    if (parent[feature] !== undefined)
+    {
+        //feature is defined without a vendor prefix, no further checks necessary
+        return parent[feature];
+    }
+
+    // the feature is not defined without a vendor prefix, so find the vendor prefix, if any,
+    // that it is defined with
+    var prefix = GetVendorPrefix(parent, feature, isAttribute);
+    
+    // if prefix is not undefined, then the feature has been found to exist with this prefix
+    if (prefix !== undefined)
+    {
+        var prefixedFeatureName = AppendPrefix(prefix, feature, isAttribute);
+        return parent[prefixedFeatureName];
+    }
+
+    //The feature does not exist.
+    //Callers should check for !==undefined as the feature itself could return
+    //a Bool which would fail a typical if(feature) check
+    return undefined;
+}
+
+// This function returns the vendor prefix found if a certain feature is defined with it.
+// It takes the same parameters at BrowserHasFeature().
+function GetVendorPrefix(parent, feature, isAttribute)
+{
+    //Known vendor prefixes
+    var VendorPrefixes = ["moz", "ms", "o", "webkit"];
+    for (vendor in VendorPrefixes)
+    {
+        //Build up the new feature name with the vendor prefix
+        var prefixedFeatureName = AppendPrefix(VendorPrefixes[vendor], feature, isAttribute);
+        if (parent[prefixedFeatureName] !== undefined)
+        {
+            //Vendor prefix version exists, return a pointer to the feature
+            return VendorPrefixes[vendor];
+        }
+    }
+    
+    // if no version of the feature with a vendor prefix has been found, return undefined
+    return undefined;
+}
+
+// This will properly capitalize the feature name and then return the feature name preceded
+// with the provided vendor prefix. If the prefix given is undefined, this function will
+// return the feature name given as is. The output of this function should not be used
+// as an indicator of whether or not a feature exists as it will return the same thing if
+// the inputted feature is undefined or is defined without a vendor prefix. It takes the 
+// same parameters at BrowserHasFeature().
+function AppendPrefix(prefix, feature, isAttribute)
+{
+    if (prefix !== undefined)
+    {
+        if (isAttribute)
+        {
+            // if a certain feature is an attribute, then it follows a different naming standard
+            // where it must be completely capitalized and have words split with an underscore
+            return prefix.toUpperCase() + "_" + feature.toUpperCase();
+        }
+        else
+        {
+            //Vendor prefixing should follow the standard convention: vendorprefixFeature
+            //Note that the feature is capitalized after the vendor prefix
+            //Therefore if the feature is window.feature, the vendor prefix version is:
+            //window.[vp]Feature where vp is the vendor prefix: 
+            //window.msFeature, window.webkitFeature, window.mozFeature, window.oFeature
+            var newFeature = feature[0].toUpperCase() + feature.substr(1, feature.length);
+
+            //Build up the new feature name with the vendor prefix
+            return prefix + newFeature;
+        }
+    }
+    else
+    {
+        return feature;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/vibration/support/helpers.js	Wed Feb 08 13:02:42 2012 -0800
@@ -0,0 +1,13 @@
+
+function supportsVibration () {
+    if (undefined !== BrowserHasFeature(navigator, "vibrate")) {
+        return true;
+    }
+    else {
+        test(function () {
+            assert_true(false, "Vibration API not found");
+        }, "Your user agent does not support the Vibration API.");
+        return false;
+    }
+}
+