/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /** * This class provides access to device accelerometer data. * @constructor */ var argscheck = require('cordova/argscheck'), utils = require("cordova/utils"), exec = require("cordova/exec"), Acceleration = require('./Acceleration'); // Is the accel sensor running? var running = false; // Keeps reference to watchAcceleration calls. var timers = {}; // Array of listeners; used to keep track of when we should call start and stop. var listeners = []; // Last returned acceleration object from native var accel = null; // Timer used when faking up devicemotion events var eventTimerId = null; // Tells native to start. function start() { exec(function (a) { var tempListeners = listeners.slice(0); accel = new Acceleration(a.x, a.y, a.z, a.timestamp); for (var i = 0, l = tempListeners.length; i < l; i++) { tempListeners[i].win(accel); } }, function (e) { var tempListeners = listeners.slice(0); for (var i = 0, l = tempListeners.length; i < l; i++) { tempListeners[i].fail(e); } }, "Accelerometer", "start", []); running = true; } // Tells native to stop. function stop() { exec(null, null, "Accelerometer", "stop", []); accel = null; running = false; } // Adds a callback pair to the listeners array function createCallbackPair(win, fail) { return { win: win, fail: fail }; } // Removes a win/fail listener pair from the listeners array function removeListeners(l) { var idx = listeners.indexOf(l); if (idx > -1) { listeners.splice(idx, 1); if (listeners.length === 0) { stop(); } } } var accelerometer = { /** * Asynchronously acquires the current acceleration. * * @param {Function} successCallback The function to call when the acceleration data is available * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) */ getCurrentAcceleration: function (successCallback, errorCallback, options) { argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments); if (cordova.platformId === "windowsphone") { exec(function (a) { accel = new Acceleration(a.x, a.y, a.z, a.timestamp); successCallback(accel); }, function (e) { errorCallback(e); }, "Accelerometer", "getCurrentAcceleration", []); return; } var p; var win = function (a) { removeListeners(p); successCallback(a); }; var fail = function (e) { removeListeners(p); if (errorCallback) { errorCallback(e); } }; p = createCallbackPair(win, fail); listeners.push(p); if (!running) { start(); } }, /** * Asynchronously acquires the acceleration repeatedly at a given interval. * * @param {Function} successCallback The function to call each time the acceleration data is available * @param {Function} errorCallback The function to call when there is an error getting the acceleration data. (OPTIONAL) * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL) * @return String The watch id that must be passed to #clearWatch to stop watching. */ watchAcceleration: function (successCallback, errorCallback, options) { argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments); // Default interval (10 sec) var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000; // Keep reference to watch id, and report accel readings as often as defined in frequency var id = utils.createUUID(); var p = createCallbackPair(function () { }, function (e) { removeListeners(p); if (errorCallback) { errorCallback(e); } }); listeners.push(p); timers[id] = { timer: window.setInterval(function () { if (accel) { successCallback(accel); } }, frequency), listeners: p }; if (running) { // If we're already running then immediately invoke the success callback // but only if we have retrieved a value, sample code does not check for null ... if (accel) { successCallback(accel); } } else { start(); } if (cordova.platformId === "browser" && !eventTimerId) { // Start firing devicemotion events if we haven't already var devicemotionEvent = new Event('devicemotion'); eventTimerId = window.setInterval(function() { window.dispatchEvent(devicemotionEvent); }, 200); } return id; }, /** * Clears the specified accelerometer watch. * * @param {String} id The id of the watch returned from #watchAcceleration. */ clearWatch: function (id) { // Stop javascript timer & remove from timer list if (id && timers[id]) { window.clearInterval(timers[id].timer); removeListeners(timers[id].listeners); delete timers[id]; if (eventTimerId && Object.keys(timers).length === 0) { // No more watchers, so stop firing 'devicemotion' events window.clearInterval(eventTimerId); eventTimerId = null; } } } }; module.exports = accelerometer;