From bf9b564bf59366557bb20c426dd3500db588925e Mon Sep 17 00:00:00 2001 From: Stanimir Karoserov Date: Mon, 28 Apr 2014 18:59:50 +0300 Subject: [PATCH] BCL: location updates according to API feedback --- Location/location.android.ts | 58 ++++++++++++++++++++++-------------- Location/location.d.ts | 54 ++++++++++++++++++++------------- Location/location.ios.ts | 48 +++++++++++++++++++++-------- Location/location_types.ts | 31 ++++++++++++------- 4 files changed, 124 insertions(+), 67 deletions(-) diff --git a/Location/location.android.ts b/Location/location.android.ts index 3ee19ba09..34f7382eb 100644 --- a/Location/location.android.ts +++ b/Location/location.android.ts @@ -1,9 +1,13 @@ import types = require("Location/location_types"); import app_module = require("Application/application"); +// merge types +declare var exports; +exports.Location = types.Location; +exports.Accuracy = types.Accuracy; + export class LocationManager { // in meters - // we might need some predefined values here like 'any' and 'high' public desiredAccuracy: number; // The minimum distance (measured in meters) a device must move horizontally before an update event is generated. @@ -15,7 +19,7 @@ export class LocationManager { public isStarted: boolean; private androidLocationManager: any; - private _locationListener: any; + private locationListener: any; private static locationFromAndroidLocation(androidLocation: android.location.Location): types.Location { var location = new types.Location(); @@ -27,7 +31,7 @@ export class LocationManager { location.speed = androidLocation.getSpeed(); location.direction = androidLocation.getBearing(); location.timestamp = new Date(androidLocation.getTime()); - location.androidNative = androidLocation; + location.android = androidLocation; //console.dump(location); return location; } @@ -53,42 +57,42 @@ export class LocationManager { return androidLocation; } - public static isLocationEnabled(): boolean { + public static isEnabled(): boolean { var criteria = new android.location.Criteria(); criteria.setAccuracy(1); // low ? fine ? who knows what 1 means (bug in android docs?) - var lm = app_module.Application.current.android.context.getSystemService('location'); + var lm = app_module.Application.current.android.context.getSystemService(android.content.Context.LOCATION_SERVICE); return (lm.getBestProvider(criteria, true) != null) ? true : false; } - public static distanceInMeters(loc1: types.Location, loc2: types.Location): number { - if (!loc1.androidNative) { - loc1.androidNative = LocationManager.androidLocationFromLocation(loc1); + public static distance(loc1: types.Location, loc2: types.Location): number { + if (!loc1.android) { + loc1.android = LocationManager.androidLocationFromLocation(loc1); } - if (!loc2.androidNative) { - loc2.androidNative = LocationManager.androidLocationFromLocation(loc2); + if (!loc2.android) { + loc2.android = LocationManager.androidLocationFromLocation(loc2); } - return loc1.androidNative.distanceTo(loc2.androidNative); + return loc1.android.distanceTo(loc2.android); } constructor() { // put some defaults - this.desiredAccuracy = types.DesiredAccuracy.HIGH; + this.desiredAccuracy = types.Accuracy.HIGH; this.updateDistance = 0; this.minimumUpdateTime = 200; this.isStarted = false; - this.androidLocationManager = app_module.Application.current.android.context.getSystemService('location'); + this.androidLocationManager = app_module.Application.current.android.context.getSystemService(android.content.Context.LOCATION_SERVICE); } //////////////////////// // monitoring //////////////////////// - public startLocationMonitoring(onLocation: (location: types.Location) => any, onError?: (error: Error) => any) { + public startLocationMonitoring(onLocation: (location: types.Location) => any, onError?: (error: Error) => any, options?: types.Options) { if (!this.isStarted) { var criteria = new android.location.Criteria(); - criteria.setAccuracy((this.desiredAccuracy === types.DesiredAccuracy.HIGH) ? 1 : 2); - this._locationListener = new android.location.LocationListener({ + criteria.setAccuracy((this.desiredAccuracy === types.Accuracy.HIGH) ? 1 : 2); + this.locationListener = new android.location.LocationListener({ onLocationChanged: function (location: android.location.Location) { if (this._onLocation) { this._onLocation(LocationManager.locationFromAndroidLocation(location)); @@ -104,10 +108,20 @@ export class LocationManager { onStatusChanged: function (arg1: string, arg2: number, arg3: android.os.Bundle): void { } }); - this._locationListener._onLocation = onLocation; - this._locationListener._onError = onError; + + if (options) { + if (options.desiredAccuracy) + this.desiredAccuracy = options.desiredAccuracy; + if (options.updateDistance) + this.updateDistance = options.updateDistance; + if (options.minimumUpdateTime) + this.minimumUpdateTime = options.minimumUpdateTime; + } + + this.locationListener._onLocation = onLocation; + this.locationListener._onError = onError; try { - this.androidLocationManager.requestLocationUpdates(long(this.minimumUpdateTime), float(this.updateDistance), criteria, this._locationListener, null); + this.androidLocationManager.requestLocationUpdates(long(this.minimumUpdateTime), float(this.updateDistance), criteria, this.locationListener, null); this.isStarted = true; } catch (e) { @@ -124,7 +138,7 @@ export class LocationManager { public stopLocationMonitoring() { if (this.isStarted) { - this.androidLocationManager.removeUpdates(this._locationListener); + this.androidLocationManager.removeUpdates(this.locationListener); this.isStarted = false; } } @@ -133,9 +147,9 @@ export class LocationManager { // other //////////////////////// - public getLastKnownLocation(): types.Location { + get lastKnownLocation(): types.Location { var criteria = new android.location.Criteria(); - criteria.setAccuracy((this.desiredAccuracy === types.DesiredAccuracy.HIGH) ? 1 : 2); + criteria.setAccuracy((this.desiredAccuracy === types.Accuracy.HIGH) ? 1 : 2); try { var providers = this.androidLocationManager.getProviders(criteria, false); var it = providers.iterator(); diff --git a/Location/location.d.ts b/Location/location.d.ts index 205c1081d..5f6d32d77 100644 --- a/Location/location.d.ts +++ b/Location/location.d.ts @@ -1,4 +1,4 @@ -export declare enum DesiredAccuracy { +export declare enum Accuracy { // in meters ANY, HIGH, @@ -26,26 +26,11 @@ export declare class Location { timestamp: Date; - public androidNative: any; // android Location - public iosNative: any; // iOS CLLocation + public android: any; // android Location + public ios: any; // iOS CLLocation } -export declare class RegionChangeListener { - onRegionEnter(region: LocationRegion); - onRegionExit(region: LocationRegion); -} - -export declare class LocationManager { - /** - * Report are location services switched ON for this device (on Android) or application (iOS) - */ - static isLocationEnabled(): boolean; - - /** - * Measure distance in meters between two locations - */ - static distanceInMeters(loc1: Location, loc2: Location): number; - +export declare class Options { /** * Specifies desired accuracy in meters. Defaults to DesiredAccuracy.HIGH */ @@ -60,6 +45,33 @@ export declare class LocationManager { * Minimum time interval between location updates, in milliseconds (android only) */ minimumUpdateTime: number; +} + +export declare class LocationManager { + /** + * Report are location services switched ON for this device (on Android) or application (iOS) + */ + static isEnabled(): boolean; + + /** + * Measure distance in meters between two locations + */ + static distance(loc1: Location, loc2: Location): number; + + /** + * Specifies desired accuracy in meters. Defaults to DesiredAccuracy.HIGH + */ + desiredAccuracy: number; + + /** + * Update distance filter in meters. Specifies how often to update. Default on iOS is no filter, on Android it is 0 meters + */ + updateDistance: number; + + /** + * Minimum time interval between location updates, in milliseconds (ignored on iOS) + */ + minimumUpdateTime: number; /** * True if location listener is already started. In this case all other start requests will be ignored @@ -71,7 +83,7 @@ export declare class LocationManager { /** * Starts location monitoring. */ - startLocationMonitoring(onLocation: (location: Location) => any, onError?: (error: Error) => any); + startLocationMonitoring(onLocation: (location: Location) => any, onError?: (error: Error) => any, options?: Options); /** * Stops location monitoring @@ -83,5 +95,5 @@ export declare class LocationManager { /** * Returns last known location from device's location services or null of no known last location */ - getLastKnownLocation(): Location; + lastKnownLocation: Location; } diff --git a/Location/location.ios.ts b/Location/location.ios.ts index 0073ad4fd..e6bfa1c06 100644 --- a/Location/location.ios.ts +++ b/Location/location.ios.ts @@ -1,4 +1,11 @@ -import types = require("Location/location_types"); + +import types = require("Location/location_types"); + +// merge types +declare var exports; +exports.Location = types.Location; +exports.Accuracy = types.Accuracy; +exports.Options = types.Options; export class LocationManager { @@ -24,7 +31,7 @@ export class LocationManager { location.speed = clLocation.speed; location.direction = clLocation.course; location.timestamp = new Date(clLocation.timestamp.timeIntervalSince1970() * 1000); - location.iosNative = clLocation; + location.ios = clLocation; //console.dump(location); return location; } @@ -40,29 +47,34 @@ export class LocationManager { return iosLocation; } - public static isLocationEnabled(): boolean { - return CoreLocation.CLLocationManager.locationServicesEnabled(); + public static isEnabled(): boolean { + if (CoreLocation.CLLocationManager.locationServicesEnabled()) { + //return CoreLocation.CLLocationManager.authorizationStatus() === CoreLocation.CLAuthorizationStatus.kCLAuthorizationStatusAuthorized; + // FIXME: issue reported https://github.com/telerik/Kimera/issues/122 + return true; + } + return false; } - public static distanceInMeters(loc1: types.Location, loc2: types.Location): number { - if (!loc1.iosNative) { - loc1.iosNative = LocationManager.iosLocationFromLocation(loc1); + public static distance(loc1: types.Location, loc2: types.Location): number { + if (!loc1.ios) { + loc1.ios = LocationManager.iosLocationFromLocation(loc1); } - if (!loc2.iosNative) { - loc2.iosNative = LocationManager.iosLocationFromLocation(loc2); + if (!loc2.ios) { + loc2.ios = LocationManager.iosLocationFromLocation(loc2); } - return loc1.iosNative.distanceFromLocation(loc2.iosNative); + return loc1.ios.distanceFromLocation(loc2.ios); } constructor() { this.isStarted = false; - this.desiredAccuracy = types.DesiredAccuracy.HIGH; + this.desiredAccuracy = types.Accuracy.HIGH; this.updateDistance = -1; // kCLDistanceFilterNone this.iosLocationManager = new CoreLocation.CLLocationManager(); } // monitoring - public startLocationMonitoring(onLocation: (location: types.Location) => any, onError?: (error: Error) => any) { + public startLocationMonitoring(onLocation: (location: types.Location) => any, onError?: (error: Error) => any, options?: types.Options) { if (!this.isStarted) { var LocationListener = Foundation.NSObject.extends({ setupWithFunctions: function (onLocation, onError) { @@ -91,12 +103,20 @@ export class LocationManager { } }); + if (options) { + if (options.desiredAccuracy) + this.desiredAccuracy = options.desiredAccuracy; + if (options.updateDistance) + this.updateDistance = options.updateDistance; + } + this.listener = new LocationListener(); this.listener.setupWithFunctions(onLocation, onError); this.iosLocationManager.delegate = this.listener; this.iosLocationManager.desiredAccuracy = this.desiredAccuracy; this.iosLocationManager.distanceFilter = this.updateDistance; this.iosLocationManager.startUpdatingLocation(); + this.isStarted = true; } else if (onError) { onError(new Error('location monitoring already started')); @@ -106,13 +126,15 @@ export class LocationManager { public stopLocationMonitoring() { if (this.isStarted) { this.iosLocationManager.stopUpdatingLocation(); + this.iosLocationManager.delegate = null; + this.listener = null; this.isStarted = false; } } // other - public getLastKnownLocation(): types.Location { + get lastKnownLocation(): types.Location { var clLocation = this.iosLocationManager.location; if (null != clLocation) { return LocationManager.locationFromCLLocation(clLocation); diff --git a/Location/location_types.ts b/Location/location_types.ts index ece51b4c2..b452e1c16 100644 --- a/Location/location_types.ts +++ b/Location/location_types.ts @@ -1,4 +1,4 @@ -export enum DesiredAccuracy { +export enum Accuracy { // in meters ANY = 300, HIGH = 3, @@ -19,8 +19,25 @@ export class Location { public timestamp: Date; - public androidNative: any; // android Location - public iosNative: any; // iOS native location + public android: any; // android Location + public ios: any; // iOS native location +} + +export declare class Options { + /** + * Specifies desired accuracy in meters. Defaults to DesiredAccuracy.HIGH + */ + public desiredAccuracy: number; + + /** + * Update distance filter in meters. Specifies how often to update. Default on iOS is no filter, on Android it is 0 meters + */ + public updateDistance: number; + + /** + * Minimum time interval between location updates, in milliseconds (ignored on iOS) + */ + public minimumUpdateTime: number; } export class LocationRegion { @@ -29,11 +46,3 @@ export class LocationRegion { public raduis: number; // radius in meters } - -// TODO: This might be implemented with two callbacks, no need of special type. -export class RegionChangeListener { - onRegionEnter(region: LocationRegion) { - } - onRegionExit(region: LocationRegion) { - } -}