You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2012/03/16 19:14:49 UTC
[10/29] ios commit: reverting my breaking commits to location. also
fixes compass!
reverting my breaking commits to location. also fixes compass!
Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/commit/242ead7e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/tree/242ead7e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/diff/242ead7e
Branch: refs/heads/master
Commit: 242ead7ec3c90f2f42e97a3b930c0b1d23b7e790
Parents: 9559aac
Author: Fil Maj <ma...@gmail.com>
Authored: Wed Mar 14 16:00:34 2012 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Fri Mar 16 10:56:50 2012 -0700
----------------------------------------------------------------------
CordovaLib/Classes/CDVLocation.h | 70 +++++---
CordovaLib/Classes/CDVLocation.m | 353 ++++++++++++++++++++++++++-------
2 files changed, 326 insertions(+), 97 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/242ead7e/CordovaLib/Classes/CDVLocation.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVLocation.h b/CordovaLib/Classes/CDVLocation.h
index 41e67bf..0254201 100755
--- a/CordovaLib/Classes/CDVLocation.h
+++ b/CordovaLib/Classes/CDVLocation.h
@@ -22,35 +22,49 @@
#import <CoreLocation/CoreLocation.h>
#import "CDVPlugin.h"
+enum CDVHeadingStatus {
+ HEADINGSTOPPED = 0,
+ HEADINGSTARTING,
+ HEADINGRUNNING,
+ HEADINGERROR
+};
+typedef NSUInteger CDVHeadingStatus;
+
+// simple object to keep track of heading information
+@interface CDVHeadingData : NSObject {
+ CDVHeadingStatus headingStatus;
+ BOOL headingRepeats;
+ CLHeading* headingInfo;
+ NSMutableArray* headingCallbacks;
+ NSString* headingFilter;
+
+}
+
+@property (nonatomic, assign) CDVHeadingStatus headingStatus;
+@property (nonatomic, assign) BOOL headingRepeats;
+@property (nonatomic, retain) CLHeading* headingInfo;
+@property (nonatomic, retain) NSMutableArray* headingCallbacks;
+@property (nonatomic, retain) NSString* headingFilter;
+
+@end
+
@interface CDVLocation : CDVPlugin <CLLocationManagerDelegate> {
- @private BOOL __locationStarted;
- @private NSString *callbackId;
- double timestamp;
- double latitude;
- double longitude;
- double altitude;
- double velocity;
- double heading;
- double accuracy;
- double altitudeAccuracy;
+
+@private BOOL __locationStarted;
+ CDVHeadingData* headingData;
}
@property (nonatomic, retain) CLLocationManager *locationManager;
-@property double timestamp;
-@property double latitude;
-@property double longitude;
-@property double altitude;
-@property double velocity;
-@property double heading;
-@property double accuracy;
-@property double altitudeAccuracy;
+@property (nonatomic, retain) CDVHeadingData* headingData;
-- (void)getLocation:(NSMutableArray*)arguments
- withDict:(NSMutableDictionary*)options;
-- (void)startLocation;
+- (BOOL) hasHeadingSupport;
-- (void)stopLocation;
+- (void)startLocation:(NSMutableArray*)arguments
+ withDict:(NSMutableDictionary*)options;
+
+- (void)stopLocation:(NSMutableArray*)arguments
+ withDict:(NSMutableDictionary*)options;
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
@@ -61,6 +75,16 @@
- (BOOL) isLocationServicesEnabled;
-@end
+- (void)getHeading:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
+- (void)returnHeadingInfo: (NSString*) callbackId keepCallback: (BOOL) bRetain;
+
+- (void)stopHeading:(NSMutableArray*)arguments
+ withDict:(NSMutableDictionary*)options;
+- (void) startHeadingWithFilter: (CLLocationDegrees) filter;
+- (void)locationManager:(CLLocationManager *)manager
+ didUpdateHeading:(CLHeading *)heading;
+
+- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager;
+@end
http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/242ead7e/CordovaLib/Classes/CDVLocation.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVLocation.m b/CordovaLib/Classes/CDVLocation.m
index 772c167..c10c365 100755
--- a/CordovaLib/Classes/CDVLocation.m
+++ b/CordovaLib/Classes/CDVLocation.m
@@ -35,7 +35,6 @@
@interface NSError(JSONMethods)
- (NSString*) JSONRepresentation;
-- (NSDictionary*) DictionaryRepresentation;
@end
@@ -45,12 +44,48 @@
@end
+
+@interface CLHeading(JSONMethods)
+
+- (NSString*) JSONRepresentation;
+
+@end
+
+#pragma mark -
+#pragma mark CDVHeadingData
+
+@implementation CDVHeadingData
+
+@synthesize headingStatus, headingRepeats, headingInfo, headingCallbacks, headingFilter;
+-(CDVHeadingData*) init
+{
+ self = (CDVHeadingData*)[super init];
+ if (self)
+ {
+ self.headingRepeats = NO;
+ self.headingStatus = HEADINGSTOPPED;
+ self.headingInfo = nil;
+ self.headingCallbacks = nil;
+ self.headingFilter = nil;
+ }
+ return self;
+}
+-(void) dealloc
+{
+ self.headingInfo = nil;
+ self.headingCallbacks = nil;
+ self.headingFilter = nil;
+ [super dealloc];
+}
+
+@end
+
#pragma mark -
#pragma mark CDVLocation
@implementation CDVLocation
-@synthesize locationManager, latitude, longitude, heading, velocity, altitude, accuracy, altitudeAccuracy, timestamp;
+@synthesize locationManager, headingData;
- (CDVPlugin*) initWithWebView:(UIWebView*)theWebView
{
@@ -60,18 +95,25 @@
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // Tells the location manager to send updates to this object
__locationStarted = NO;
- self.timestamp = 0.0;
- self.latitude = 0.0;
- self.longitude = 0.0;
- self.altitude = 0.0;
- self.accuracy = 0.0;
- self.heading = 0.0;
- self.velocity = 0.0;
- self.altitudeAccuracy = 0.0;
+ self.headingData = nil;
}
return self;
}
+- (BOOL) hasHeadingSupport
+{
+ BOOL headingInstancePropertyAvailable = [self.locationManager respondsToSelector:@selector(headingAvailable)]; // iOS 3.x
+ BOOL headingClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(headingAvailable)]; // iOS 4.x
+
+ if (headingInstancePropertyAvailable) { // iOS 3.x
+ return [(id)self.locationManager headingAvailable];
+ } else if (headingClassPropertyAvailable) { // iOS 4.x
+ return [CLLocationManager headingAvailable];
+ } else { // iOS 2.x
+ return NO;
+ }
+}
+
- (BOOL) isAuthorized
{
BOOL authorizationStatusClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+
@@ -104,10 +146,28 @@
}
}
-- (void) startLocation
+- (void) startLocation:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
{
if (![self isLocationServicesEnabled])
{
+ BOOL forcePrompt = NO;
+ // if forcePrompt is true iPhone will still show the "Location Services not active." Settings | Cancel prompt.
+ if ([options objectForKey:kPGLocationForcePromptKey])
+ {
+ forcePrompt = [[options objectForKey:kPGLocationForcePromptKey] boolValue];
+ }
+
+ if (!forcePrompt)
+ {
+ NSError* error = [NSError errorWithDomain:kPGLocationErrorDomain code:1 userInfo:
+ [NSDictionary dictionaryWithObject:@"Location services is not enabled" forKey:NSLocalizedDescriptionKey]];
+ NSLog(@"%@", [error JSONRepresentation]);
+
+ NSString* jsCallback = [NSString stringWithFormat:@"navigator.geolocation.setError(%@);", [error JSONRepresentation]];
+ [super writeJavascript:jsCallback];
+
+ return;
+ }
}
if (![self isAuthorized])
{
@@ -117,18 +177,12 @@
code = [CLLocationManager authorizationStatus];
}
- CDVPluginResult* result = nil;
- NSString* jsString = nil;
-
NSError* error = [NSError errorWithDomain:NSCocoaErrorDomain code:code userInfo:
[NSDictionary dictionaryWithObject:@"App is not authorized for Location Services" forKey:NSLocalizedDescriptionKey]];
-
NSLog(@"%@", [error JSONRepresentation]);
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION messageAsDictionary:[error DictionaryRepresentation]];
- jsString = [result toErrorCallbackString:callbackId];
-
- [super writeJavascript:jsString];
+ NSString* jsCallback = [NSString stringWithFormat:@"navigator.geolocation.setError(%@);", [error JSONRepresentation]];
+ [super writeJavascript:jsCallback];
return;
}
@@ -139,8 +193,7 @@
[self.locationManager stopUpdatingLocation];
[self.locationManager startUpdatingLocation];
__locationStarted = YES;
- // TODO: what should we do about all this stuff?
- /*
+
if ([options objectForKey:kPGLocationDistanceFilterKey])
{
CLLocationDistance distanceFilter = [(NSString *)[options objectForKey:kPGLocationDistanceFilterKey] doubleValue];
@@ -170,92 +223,252 @@
self.locationManager.desiredAccuracy = desiredAccuracy;
}
- */
}
-- (void) stopLocation
+- (void) stopLocation:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
{
if (__locationStarted)
{
if (![self isLocationServicesEnabled]) {
return;
}
-
+
[self.locationManager stopUpdatingLocation];
__locationStarted = NO;
}
}
-- (void) getLocation:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)options
+- (void) locationManager:(CLLocationManager *)manager
+ didUpdateToLocation:(CLLocation *)newLocation
+ fromLocation:(CLLocation *)oldLocation
+{
+
+ NSString* jsCallback = [NSString stringWithFormat:@"navigator.geolocation.setLocation(%@);", [newLocation JSONRepresentation]];
+ [super writeJavascript:jsCallback];
+}
+// called to get the current heading
+// Will call location manager to startUpdatingHeading if necessary
+
+- (void)getHeading:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ NSString* callbackId = [arguments objectAtIndex:0];
+ NSNumber* repeats = [options valueForKey:@"repeats"]; // indicates this call will be repeated at regular intervals
+
+ if ([self hasHeadingSupport] == NO)
+ {
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageToErrorObject:20];
+ [super writeJavascript:[result toErrorCallbackString:callbackId]];
+ } else {
+ // heading retrieval does is not affected by disabling locationServices and authorization of app for location services
+ if (!self.headingData) {
+ self.headingData = [[[CDVHeadingData alloc] init] autorelease];
+ }
+ CDVHeadingData* hData = self.headingData;
+
+ if (repeats != nil) {
+ hData.headingRepeats = YES;
+ }
+ if (!hData.headingCallbacks) {
+ hData.headingCallbacks = [NSMutableArray arrayWithCapacity:1];
+ }
+ // add the callbackId into the array so we can call back when get data
+ [hData.headingCallbacks addObject:callbackId];
+
+ if (hData.headingStatus != HEADINGRUNNING && hData.headingStatus != HEADINGERROR) {
+ // Tell the location manager to start notifying us of heading updates
+ [self startHeadingWithFilter: 0.2];
+ }
+ else {
+ [self returnHeadingInfo: callbackId keepCallback:NO];
+ }
+ }
+
+
+}
+// called to request heading updates when heading changes by a certain amount (filter)
+- (void)watchHeadingFilter:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ NSString* callbackId = [arguments objectAtIndex:0];
+ NSNumber* filter = [options valueForKey:@"filter"];
+ CDVHeadingData* hData = self.headingData;
+ if ([self hasHeadingSupport] == NO) {
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageToErrorObject:20];
+ [super writeJavascript:[result toErrorCallbackString:callbackId]];
+ } else {
+ if (!hData) {
+ self.headingData = [[[CDVHeadingData alloc] init] autorelease];
+ hData = self.headingData;
+ }
+ if (hData.headingStatus != HEADINGRUNNING) {
+ // Tell the location manager to start notifying us of heading updates
+ [self startHeadingWithFilter: [filter doubleValue]];
+ } else {
+ // if already running check to see if due to existing watch filter
+ if (hData.headingFilter && ![hData.headingFilter isEqualToString:callbackId]){
+ // new watch filter being specified
+ // send heading data one last time to clear old successCallback
+ [self returnHeadingInfo:hData.headingFilter keepCallback: NO];
+ }
+
+ }
+ // save the new filter callback and update the headingFilter setting
+ hData.headingFilter = callbackId;
+ // check if need to stop and restart in order to change value???
+ self.locationManager.headingFilter = [filter doubleValue];
+ }
+}
+- (void)returnHeadingInfo: (NSString*) callbackId keepCallback: (BOOL) bRetain
{
CDVPluginResult* result = nil;
NSString* jsString = nil;
- callbackId = [arguments objectAtIndex:0];
+ CDVHeadingData* hData = self.headingData;
- if (!__locationStarted)
- {
- [self startLocation];
+ if (hData && hData.headingStatus == HEADINGERROR) {
+ // return error
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageToErrorObject:0];
+ jsString = [result toErrorCallbackString:callbackId];
+ } else if (hData && hData.headingStatus == HEADINGRUNNING && hData.headingInfo) {
+ // if there is heading info, return it
+ CLHeading* hInfo = hData.headingInfo;
+ NSMutableDictionary* returnInfo = [NSMutableDictionary dictionaryWithCapacity:4];
+ NSNumber* timestamp = [NSNumber numberWithDouble:([hInfo.timestamp timeIntervalSince1970]*1000)];
+ [returnInfo setObject:timestamp forKey:@"timestamp"];
+ [returnInfo setObject:[NSNumber numberWithDouble: hInfo.magneticHeading] forKey:@"magneticHeading"];
+ id trueHeading = __locationStarted ? (id)[NSNumber numberWithDouble:hInfo.trueHeading]:(id)[NSNull null];
+ [returnInfo setObject:trueHeading forKey:@"trueHeading"];
+ [returnInfo setObject:[NSNumber numberWithDouble: hInfo.headingAccuracy] forKey:@"headingAccuracy"];
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: returnInfo];
+ [result setKeepCallbackAsBool:bRetain];
+
+ jsString = [result toSuccessCallbackString:callbackId];
+ }
+ if (jsString) {
+ [super writeJavascript:jsString];
}
- NSMutableDictionary *currentLocation = [NSMutableDictionary dictionaryWithCapacity:8];
- [currentLocation setValue:[NSNumber numberWithDouble:self.timestamp] forKey:@"timestamp"];
- [currentLocation setValue:[NSNumber numberWithDouble:self.latitude] forKey:@"latitude"];
- [currentLocation setValue:[NSNumber numberWithDouble:self.longitude] forKey:@"longitude"];
- [currentLocation setValue:[NSNumber numberWithDouble:self.altitude] forKey:@"altitude"];
- [currentLocation setValue:[NSNumber numberWithDouble:self.heading] forKey:@"heading"];
- [currentLocation setValue:[NSNumber numberWithDouble:self.accuracy] forKey:@"accuracy"];
- [currentLocation setValue:[NSNumber numberWithDouble:self.velocity] forKey:@"velocity"];
- [currentLocation setValue:[NSNumber numberWithDouble:self.altitudeAccuracy] forKey:@"altitudeAccuracy"];
-
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:currentLocation];
- jsString = [result toSuccessCallbackString:callbackId];
- [self writeJavascript:jsString];
+
}
-- (void) locationManager:(CLLocationManager *)manager
- didUpdateToLocation:(CLLocation *)newLocation
- fromLocation:(CLLocation *)oldLocation
+- (void) stopHeading:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
+{
+ CDVHeadingData* hData = self.headingData;
+ if (hData && hData.headingStatus != HEADINGSTOPPED)
+ {
+ if (hData.headingFilter) {
+ // callback one last time to clear callback
+ [self returnHeadingInfo:hData.headingFilter keepCallback:NO];
+ hData.headingFilter = nil;
+ }
+ [self.locationManager stopUpdatingHeading];
+ self.headingData = nil;
+ }
+}
+
+
+// helper method to check the orientation and start updating headings
+- (void) startHeadingWithFilter: (CLLocationDegrees) filter
+{
+ if ([self.locationManager respondsToSelector: @selector(headingOrientation)]) {
+ UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
+ if (currentOrientation != UIDeviceOrientationUnknown) {
+ CDVViewController* pgViewController = (CDVViewController*)self.viewController;
+
+ if ([pgViewController.supportedOrientations containsObject:
+ [NSNumber numberWithInt:currentOrientation]]) {
+
+ self.locationManager.headingOrientation = (CLDeviceOrientation)currentOrientation;
+ // FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same
+ }
+ }
+ }
+ self.locationManager.headingFilter = filter;
+ [self.locationManager startUpdatingHeading];
+ self.headingData.headingStatus = HEADINGSTARTING;
+}
+- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
- self.timestamp = [newLocation.timestamp timeIntervalSince1970] * 1000.0;
- self.latitude = newLocation.coordinate.latitude;
- self.longitude = newLocation.coordinate.longitude;
- self.altitude = newLocation.altitude;
- self.heading = newLocation.course;
- self.velocity = newLocation.speed;
- self.accuracy = newLocation.horizontalAccuracy;
- self.altitudeAccuracy = newLocation.verticalAccuracy;
+ return YES;
}
+- (void) locationManager:(CLLocationManager *)manager
+ didUpdateHeading:(CLHeading *)heading
+{
+ CDVHeadingData* hData = self.headingData;
+ // save the data for next call into getHeadingData
+ hData.headingInfo = heading;
+
+ if (hData.headingStatus == HEADINGSTARTING) {
+ hData.headingStatus = HEADINGRUNNING; // so returnHeading info will work
+ //this is the first update
+ for (NSString* callbackId in hData.headingCallbacks) {
+ [self returnHeadingInfo:callbackId keepCallback:NO];
+ }
+ [hData.headingCallbacks removeAllObjects];
+ if (!hData.headingRepeats && !hData.headingFilter) {
+ [self stopHeading:nil withDict:nil];
+ }
+ }
+ if (hData.headingFilter) {
+ [self returnHeadingInfo: hData.headingFilter keepCallback:YES];
+ }
+ hData.headingStatus = HEADINGRUNNING; // to clear any error
+
+}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"locationManager::didFailWithError %@", [error localizedFailureReason]);
+ NSString* jsCallback = @"";
+ // Compass Error
+ if ([error code] == kCLErrorHeadingFailure)
+ {
+ CDVHeadingData* hData = self.headingData;
+ if (hData) {
+ if (hData.headingStatus == HEADINGSTARTING) {
+ // heading error during startup - report error
+ for (NSString* callbackId in hData.headingCallbacks) {
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageToErrorObject:0];
+ [super writeJavascript: [result toErrorCallbackString:callbackId]];
+ }
+ [hData.headingCallbacks removeAllObjects];
+ } // else for frequency watches next call to getCurrentHeading will report error
+ else if (hData.headingFilter) {
+ CDVPluginResult* resultFilter = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageToErrorObject:0];
+ [super writeJavascript: [resultFilter toErrorCallbackString:hData.headingFilter]];
+ }
+ hData.headingStatus = HEADINGERROR;
+ }
+ }
// Location Error
- if ([error code] != kCLErrorHeadingFailure)
+ else
{
/*
- W3C PositionError
- PositionError.UNKNOWN_ERROR = 0; // equivalent to kCLErrorLocationUnknown=0
- PositionError.PERMISSION_DENIED = 1; // equivalent to kCLErrorDenied=1
- PositionError.POSITION_UNAVAILABLE = 2; // equivalent to kCLErrorNetwork=2
+ W3C PositionError
+ PositionError.UNKNOWN_ERROR = 0; // equivalent to kCLErrorLocationUnknown=0
+ PositionError.PERMISSION_DENIED = 1; // equivalent to kCLErrorDenied=1
+ PositionError.POSITION_UNAVAILABLE = 2; // equivalent to kCLErrorNetwork=2
- (any other errors are translated to PositionError.UNKNOWN_ERROR)
+ (any other errors are translated to PositionError.UNKNOWN_ERROR)
*/
if (error.code > kCLErrorNetwork) {
error = [NSError errorWithDomain:error.domain code:kCLErrorLocationUnknown userInfo:error.userInfo];
}
- CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[error DictionaryRepresentation]];
- NSString* jsString = [result toErrorCallbackString:callbackId];
- [self writeJavascript:jsString];
+
+ jsCallback = [NSString stringWithFormat:@"navigator.geolocation.setError(%@);", [error JSONRepresentation]];
}
+
+ [super writeJavascript:jsCallback];
- [self stopLocation];
+ [self.locationManager stopUpdatingLocation];
+ __locationStarted = NO;
}
- (void) dealloc
{
self.locationManager.delegate = nil;
self.locationManager = nil;
+ self.headingData = nil;
[super dealloc];
}
@@ -270,8 +483,8 @@
{
return [NSString stringWithFormat:
@"{ timestamp: %.00f, \
- latitude: %f, longitude: %f, altitude: %.02f, heading: %.02f, velocity: %.02f, accuracy: %.02f, altitudeAccuracy: %.02f \
- }",
+ coords: { latitude: %f, longitude: %f, altitude: %.02f, heading: %.02f, speed: %.02f, accuracy: %.02f, altitudeAccuracy: %.02f } \
+ }",
[self.timestamp timeIntervalSince1970] * 1000.0,
self.coordinate.latitude,
self.coordinate.longitude,
@@ -298,13 +511,5 @@
[self localizedDescription]
];
}
-- (NSDictionary*) DictionaryRepresentation
-{
- NSMutableDictionary *error = [NSMutableDictionary dictionaryWithCapacity:2];
- [error setValue:[NSNumber numberWithInteger:self.code] forKey:@"code"];
- [error setValue:[self localizedDescription] forKey:@"message"];
-
- return error;
-}
-@end
+@end
\ No newline at end of file