Skip to content

Commit

Permalink
extract GPS data from gogo inflight tracker when available
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronpk committed Dec 14, 2018
1 parent c6208c4 commit bf726f4
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 4 deletions.
23 changes: 22 additions & 1 deletion GPSLogger/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
</constraints>
</view>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" distribution="equalSpacing" alignment="center" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="9iG-7h-Ohb">
<rect key="frame" x="20" y="172" width="335" height="257.5"/>
<rect key="frame" x="20" y="172" width="335" height="322"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" distribution="fillProportionally" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="AEs-fE-5WC" userLabel="Sent Data View">
<rect key="frame" x="0.0" y="0.0" width="335" height="78.5"/>
Expand Down Expand Up @@ -402,13 +402,32 @@ IAogA
</mask>
</variation>
</view>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="uhI-Kg-au0" userLabel="Flight Info View">
<rect key="frame" x="0.0" y="277.5" width="335" height="44.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="FLIGHT INFO" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cDx-y5-EG5">
<rect key="frame" x="0.0" y="0.0" width="335" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.37715041040000002" green="0.37715041040000002" blue="0.37715041040000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text=" " textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" minimumFontSize="14" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aoP-26-thz">
<rect key="frame" x="0.0" y="17" width="335" height="27.5"/>
<fontDescription key="fontDescription" name="OpenSans-Light" family="Open Sans" pointSize="20"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="FAz-8W-iDJ" firstAttribute="leading" secondItem="9iG-7h-Ohb" secondAttribute="leading" id="39d-Id-jax"/>
<constraint firstAttribute="trailing" secondItem="FAz-8W-iDJ" secondAttribute="trailing" id="8gu-GY-o3l"/>
<constraint firstAttribute="trailing" secondItem="tIR-7Y-EzQ" secondAttribute="trailing" id="9zl-mW-13Z"/>
<constraint firstItem="AEs-fE-5WC" firstAttribute="leading" secondItem="tIR-7Y-EzQ" secondAttribute="leading" id="OSz-wJ-i1H"/>
<constraint firstItem="uhI-Kg-au0" firstAttribute="leading" secondItem="9iG-7h-Ohb" secondAttribute="leading" id="Res-SX-0bo"/>
<constraint firstItem="tIR-7Y-EzQ" firstAttribute="leading" secondItem="9iG-7h-Ohb" secondAttribute="leading" id="bVL-KY-bY2"/>
<constraint firstAttribute="trailing" secondItem="uhI-Kg-au0" secondAttribute="trailing" id="biq-Ca-sND"/>
</constraints>
</stackView>
</subviews>
Expand Down Expand Up @@ -447,6 +466,8 @@ IAogA
<connections>
<outlet property="currentModeImage" destination="kvv-zo-7Tv" id="tOC-J3-9Fr"/>
<outlet property="currentModeLabel" destination="3p1-MV-Fnk" id="KjG-uk-bE4"/>
<outlet property="flightInfoView" destination="uhI-Kg-au0" id="brr-hG-YmZ"/>
<outlet property="flightSummary" destination="aoP-26-thz" id="uWp-A2-a7V"/>
<outlet property="locationAgeLabel" destination="FeB-bn-woc" id="I4q-If-q63"/>
<outlet property="locationAltitudeLabel" destination="tzf-yA-Lrh" id="VuF-QB-TXb"/>
<outlet property="locationLabel" destination="ItY-6C-yMI" id="T7t-0O-z3B"/>
Expand Down
3 changes: 3 additions & 0 deletions GPSLogger/FirstViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,8 @@
@property (strong, nonatomic) IBOutlet UIButton *tripStartStopButton;
- (IBAction)tripStartStopWasTapped:(id)sender;

@property (strong, nonatomic) IBOutlet UIView *flightInfoView;
@property (strong, nonatomic) IBOutlet UILabel *flightSummary;

@end

16 changes: 14 additions & 2 deletions GPSLogger/FirstViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,12 @@ - (void)refreshView {
motionTypeString = @"driving";
else if(activity.stationary)
motionTypeString = @"stationary";
else
motionTypeString = nil;
else {
if([GLManager sharedManager].lastMotionString)
motionTypeString = [GLManager sharedManager].lastMotionString;
else
motionTypeString = nil;
}

if(motionTypeString != nil) {
self.motionTypeLabel.text = motionTypeString;
Expand All @@ -195,6 +199,14 @@ - (void)refreshView {
}];

[self updateTripState];

if([GLManager sharedManager].currentFlightSummary) {
self.flightSummary.text = [GLManager sharedManager].currentFlightSummary;
self.flightInfoView.hidden = NO;
} else {
self.flightSummary.text = @"";
self.flightInfoView.hidden = YES;
}

//if(![GLManager sharedManager].sendInProgress)
// [self sendingStarted];
Expand Down
2 changes: 2 additions & 0 deletions GPSLogger/GLManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ typedef enum {
@property (strong, nonatomic, readonly) CLLocation *lastLocation;
@property (strong, nonatomic, readonly) NSDictionary *lastLocationDictionary;
@property (strong, nonatomic, readonly) CMMotionActivity *lastMotion;
@property (strong, nonatomic, readonly) NSString *lastMotionString;
@property (strong, nonatomic, readonly) NSNumber *lastStepCount;
@property (strong, nonatomic, readonly) NSDate *lastSentDate;
@property (strong, nonatomic, readonly) NSString *lastLocationName;
@property (strong, nonatomic, readonly) NSString *currentFlightSummary;

- (void)startAllUpdates;
- (void)stopAllUpdates;
Expand Down
154 changes: 153 additions & 1 deletion GPSLogger/GLManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ @interface GLManager()
@property (strong, nonatomic) LOLDatabase *db;
@property (strong, nonatomic) FMDatabase *tripdb;

@property (strong, nonatomic) NSTimer *flightTrackerTimer;

@end

@implementation GLManager
Expand All @@ -50,6 +52,10 @@ @implementation GLManager
CLLocationDistance _currentTripDistanceCached;
AFHTTPSessionManager *_httpClient;

// Keep track of whether location updates were stopped by the in-flight tracker
bool _stoppedFromInFlightTracker = NO;
AFHTTPSessionManager *_flightHTTPClient;

+ (GLManager *)sharedManager {
static GLManager *_instance = nil;

Expand All @@ -71,6 +77,7 @@ + (GLManager *)sharedManager {
[_instance setupHTTPClient];
[_instance restoreTrackingState];
[_instance initializeNotifications];
[_instance startFlightTrackerTimer];
}
}

Expand Down Expand Up @@ -310,6 +317,9 @@ - (void)setupHTTPClient {
_httpClient.responseSerializer = [AFJSONResponseSerializer serializer];
}

_flightHTTPClient = [[AFHTTPSessionManager manager] init];
_flightHTTPClient.responseSerializer = [AFJSONResponseSerializer serializer];

_deviceId = [self deviceId];
}

Expand Down Expand Up @@ -1066,8 +1076,150 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center
completionHandler(UNNotificationPresentationOptionAlert);
}

#pragma mark -
#pragma mark - In-Flight Tracker

/*
The goal of this code is to use the in-flight GPS tracker if available.
If the phone is connected to an in-flight wifi system like "gogoinflight", then
it should attempt to retrieve the GPS data from the plane.
When available, this should take precedence over the phone's own location services.
If the currently connected wifi name is "gogoinflight",
then attempt to fetch the GPS data URL.
If data is available, then stop local location updates.
If the request fails, start local location updates again.
If the currently connected wifi name is not "gogoinflight" then start local updates.
*/

- (void)startFlightTrackerTimer {
self.flightTrackerTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(retrieveCurrentFlightData)
userInfo:nil
repeats:NO];
}

- (void)retrieveCurrentFlightData {
// Check if the current wifi name matches a known flight provider
if(true || [@"gogoinflight" isEqualToString:[GLManager currentWifiHotSpotName]]) {

// Make a request to the in-flight data URL
NSString *endpoint = @"http://airborne.gogoinflight.com/abp/ws/absServices/statusTray";
[_flightHTTPClient GET:endpoint parameters:NULL progress:NULL success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// If we got in-flight data, stop local updates
_stoppedFromInFlightTracker = YES;
[self disableTracking];

// Record this data point
NSDictionary *info = [[responseObject objectForKey:@"Response"] objectForKey:@"flightInfo"];

_currentFlightSummary = [NSString stringWithFormat:@"%@ %@ to %@\nTail number %@",
[info valueForKey:@"flightNumberInfo"],
[info valueForKey:@"departureAirportCodeIata"],
[info valueForKey:@"destinationAirportCodeIata"],
[info valueForKey:@"tailNumber"]
];

// Create a fake datapoint for the UI to grab
CLLocation *loc = [self currentLocationFromGogoDictionary:info];

self.lastLocation = loc;
self.lastLocationDictionary = [self currentDictionaryFromGogoDictionary:info];
_lastMotionString = @"flying";

[self writeCurrentLocationToHistory];

// Start a new timer to check again
[self startFlightTrackerTimer];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"Error retrieving in-flight data");
[self _resetFlightTrackerAndStartAgain];
}];

} else {
[self _resetFlightTrackerAndStartAgain];
}
}

- (void)writeCurrentLocationToHistory {
[[NSNotificationCenter defaultCenter] postNotificationName:GLNewDataNotification object:self];

[self.db accessCollection:GLLocationQueueName withBlock:^(id<LOLDatabaseAccessor> accessor) {
NSString *timestamp = [GLManager iso8601DateStringFromDate:self.lastLocation.timestamp];
NSDictionary *update = self.lastLocationDictionary;
[accessor setDictionary:update forKey:timestamp];
}];

if(self.tripInProgress) {
[self.tripdb executeUpdate:@"INSERT INTO trips (timestamp, latitude, longitude) VALUES (?, ?, ?)", [NSNumber numberWithInt:[self.lastLocation.timestamp timeIntervalSince1970]], [NSNumber numberWithDouble:self.lastLocation.coordinate.latitude], [NSNumber numberWithDouble:self.lastLocation.coordinate.longitude]];
_currentTripHasNewData = YES;
}
}

- (NSDictionary *)currentDictionaryFromGogoDictionary:(NSDictionary *)info {
double latitude = [(NSNumber *)[info valueForKey:@"latitude"] doubleValue];
double longitude = [(NSNumber *)[info valueForKey:@"longitude"] doubleValue];

// Create the dictionary with our standard properties
NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithDictionary:@{
@"timestamp": [info valueForKey:@"utcTime"],
@"altitude": [info valueForKey:@"altitude"],
@"speed": [NSNumber numberWithDouble:([(NSNumber *)[info valueForKey:@"hspeed"] doubleValue] * 0.45)],
@"horizontal_accuracy": @11,
@"motion": @[@"flying"],
@"battery_state": [self currentBatteryState],
@"battery_level": [self currentBatteryLevel],
@"wifi": [GLManager currentWifiHotSpotName],
@"source": @"gogo",
@"flight_data": info,
}];

NSDictionary *update = @{
@"type": @"Feature",
@"geometry": @{
@"type": @"Point",
@"coordinates": @[
[NSNumber numberWithDouble:longitude],
[NSNumber numberWithDouble:latitude]
]
},
@"properties": properties
};

return update;
}

- (CLLocation *)currentLocationFromGogoDictionary:(NSDictionary *)info {
double latitude = [(NSNumber *)[info valueForKey:@"latitude"] doubleValue];
double longitude = [(NSNumber *)[info valueForKey:@"longitude"] doubleValue];
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(latitude, longitude);
NSDate *timestamp = NSDate.date; // TODO: parse the ISO8601 timestamp from info

CLLocation *loc = [[CLLocation alloc] initWithCoordinate:coord
altitude:[(NSNumber *)[info valueForKey:@"altitude"] doubleValue]
horizontalAccuracy:11
verticalAccuracy:11
course:0
speed:[[NSNumber numberWithDouble:([(NSNumber *)[info valueForKey:@"hspeed"] doubleValue] * 0.45)] doubleValue]
timestamp:timestamp];
return loc;
}

- (void)_resetFlightTrackerAndStartAgain {
// If we had previously stopped updates because we had in-flight data, start them again
if(_stoppedFromInFlightTracker) {
[self enableTracking];
_stoppedFromInFlightTracker = NO;
}
_lastMotionString = nil;
_currentFlightSummary = nil;
// Check for in-flight data again soon
[self startFlightTrackerTimer];
}

#pragma mark -

- (BOOL)defaultsKeyExists:(NSString *)key {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
Expand Down

0 comments on commit bf726f4

Please sign in to comment.