/* * Copyright 2013 Research In Motion Limited. * * Licensed 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. */ /* global Windows, WinJS */ var PositionError = require('./PositionError'); var callbacks = {}; var locs = {}; // constants var FALLBACK_EPSILON = 0.001; function ensureAndCreateLocator () { var deferral; var loc = new Windows.Devices.Geolocation.Geolocator(); if (typeof Windows.Devices.Geolocation.Geolocator.requestAccessAsync === 'function') { deferral = Windows.Devices.Geolocation.Geolocator.requestAccessAsync().then(function (result) { if (result === Windows.Devices.Geolocation.GeolocationAccessStatus.allowed) { return loc; } return WinJS.Promise.wrapError({ code: PositionError.PERMISSION_DENIED, message: 'Geolocation access has not been allowed by user.' }); }); } else { deferral = WinJS.Promise.wrap(loc); } return deferral; } function createErrorCode (loc) { /* eslint-disable no-fallthrough */ switch (loc.locationStatus) { case Windows.Devices.Geolocation.PositionStatus.initializing: // This status indicates that a location device is still initializing case Windows.Devices.Geolocation.PositionStatus.noData: // No location data is currently available case Windows.Devices.Geolocation.PositionStatus.notInitialized: // This status indicates that the app has not yet requested // location data by calling GetGeolocationAsync() or // registering an event handler for the positionChanged event. case Windows.Devices.Geolocation.PositionStatus.notAvailable: // Location is not available on this version of Windows return PositionError.POSITION_UNAVAILABLE; case Windows.Devices.Geolocation.PositionStatus.disabled: // The app doesn't have permission to access location, // either because location has been turned off. return PositionError.PERMISSION_DENIED; default: break; } } /* eslint-enable no-fallthrough */ function createResult (pos) { var res = { accuracy: pos.coordinate.accuracy, heading: pos.coordinate.heading, velocity: pos.coordinate.speed, altitudeAccuracy: pos.coordinate.altitudeAccuracy, timestamp: pos.coordinate.timestamp }; if (pos.coordinate.point) { res.latitude = pos.coordinate.point.position.latitude; res.longitude = pos.coordinate.point.position.longitude; res.altitude = pos.coordinate.point.position.altitude; } else { // compatibility with old windows8.0 api res.latitude = pos.coordinate.latitude; res.longitude = pos.coordinate.longitude; res.altitude = pos.coordinate.altitude; } return res; } module.exports = { getLocation: function (success, fail, args, env) { ensureAndCreateLocator().done(function (loc) { if (loc) { var highAccuracy = args[0]; var maxAge = args[1]; loc.desiredAccuracy = highAccuracy ? Windows.Devices.Geolocation.PositionAccuracy.high : Windows.Devices.Geolocation.PositionAccuracy.default; loc.reportInterval = maxAge || 0; loc.getGeopositionAsync().then( function (pos) { success(createResult(pos)); }, function (err) { fail({ code: createErrorCode(loc), message: err.message }); } ); } else { fail({ code: PositionError.POSITION_UNAVAILABLE, message: 'You do not have the required location services present on your system.' }); } }, fail); }, addWatch: function (success, fail, args, env) { ensureAndCreateLocator().done(function (loc) { var clientId = args[0]; var highAccuracy = args[1]; var onPositionChanged = function (e) { success(createResult(e.position), { keepCallback: true }); }; var onStatusChanged = function (e) { switch (e.status) { case Windows.Devices.Geolocation.PositionStatus.noData: case Windows.Devices.Geolocation.PositionStatus.notAvailable: fail({ code: PositionError.POSITION_UNAVAILABLE, message: 'Data from location services is currently unavailable or you do not have the required location services present on your system.' }); break; case Windows.Devices.Geolocation.PositionStatus.disabled: fail({ code: PositionError.PERMISSION_DENIED, message: 'Your location is currently turned off.' }); break; // case Windows.Devices.Geolocation.PositionStatus.initializing: // case Windows.Devices.Geolocation.PositionStatus.ready: default: break; } }; loc.desiredAccuracy = highAccuracy ? Windows.Devices.Geolocation.PositionAccuracy.high : Windows.Devices.Geolocation.PositionAccuracy.default; if (cordova.platformId === 'windows') { // eslint-disable-line no-undef // 'positionchanged' event fails with error below if movementThreshold is not set // JavaScript runtime error: Operation aborted // You must set the MovementThreshold property or the ReportInterval property before adding event handlers. // WinRT information: You must set the MovementThreshold property or the ReportInterval property before adding event handlers if (Number.EPSILON) { loc.movementThreshold = Number.EPSILON; } else { loc.movementThreshold = FALLBACK_EPSILON; } } loc.addEventListener('positionchanged', onPositionChanged); loc.addEventListener('statuschanged', onStatusChanged); callbacks[clientId] = { pos: onPositionChanged, status: onStatusChanged }; locs[clientId] = loc; }, fail); }, clearWatch: function (success, fail, args, env) { var clientId = args[0]; var callback = callbacks[clientId]; var loc = locs[clientId]; if (callback && loc) { loc.removeEventListener('positionchanged', callback.pos); loc.removeEventListener('statuschanged', callback.status); delete callbacks[clientId]; delete locs[clientId]; } success(); } }; require('cordova/exec/proxy').add('Geolocation', module.exports);