From 4f65b3021310c07d57cfc4f3cee3f236d1d002e2 Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Thu, 25 Jul 2024 14:30:24 -0400 Subject: [PATCH 1/9] recommit with latest code from master --- Example/Example/AppDelegate.swift | 2 +- Example/Example/Info.plist | 53 ++-- Example/Example/Utils.swift | 2 + RadarSDK.xcodeproj/project.pbxproj | 16 ++ RadarSDK/Include/Radar.h | 9 + RadarSDK/Include/RadarBeacon.h | 1 + RadarSDK/Include/RadarEvent.h | 4 +- RadarSDK/Include/RadarTrackingOptions.h | 2 + RadarSDK/NSData+GZIP.h | 43 +++ RadarSDK/NSData+GZIP.m | 135 +++++++++ RadarSDK/Radar.m | 33 +++ RadarSDK/RadarAPIClient.h | 2 + RadarSDK/RadarAPIClient.m | 9 + RadarSDK/RadarBeacon.m | 5 + RadarSDK/RadarBeaconManager.m | 16 ++ RadarSDK/RadarEvent.m | 16 +- RadarSDK/RadarIndoorSurvey.h | 35 +++ RadarSDK/RadarIndoorSurvey.m | 351 ++++++++++++++++++++++++ RadarSDK/RadarLocationManager.m | 85 +++++- RadarSDK/RadarLogger.m | 30 +- RadarSDK/RadarSdkConfiguration.m | 9 + RadarSDK/RadarSettings.m | 4 +- RadarSDK/RadarTrackingOptions.m | 10 +- RadarSDK/RadarVerificationManager.m | 1 + 24 files changed, 828 insertions(+), 45 deletions(-) create mode 100644 RadarSDK/NSData+GZIP.h create mode 100644 RadarSDK/NSData+GZIP.m create mode 100644 RadarSDK/RadarIndoorSurvey.h create mode 100644 RadarSDK/RadarIndoorSurvey.m diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index 95d4dec18..6ddbdce3c 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -26,7 +26,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIWindowSceneDelegate, UN self.requestLocationPermissions() // Replace with a valid test publishable key - Radar.initialize(publishableKey: "prj_test_pk_0000000000000000000000000000000000000000") + Radar.initialize(publishableKey: "prj_test_pk_2236cce4dabfd26f891738e119b66270be6d3d01") Radar.setUserId("testUserId") Radar.setMetadata([ "foo": "bar" ]) Radar.setDelegate(self) diff --git a/Example/Example/Info.plist b/Example/Example/Info.plist index 246fd3489..690488078 100644 --- a/Example/Example/Info.plist +++ b/Example/Example/Info.plist @@ -20,6 +20,34 @@ 1 LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSPinnedDomains + + api-verified.radar.io + + NSIncludesSubdomains + + NSPinnedLeafIdentities + + + SPKI-SHA256-BASE64 + 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= + + + SPKI-SHA256-BASE64 + 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= + + + + + + NSBluetoothAlwaysUsageDescription + Please enable Bluetooth for indoors location + NSBluetoothPeripheralUsageDescription + Please enable Bluetooth for indoors location NSLocationAlwaysAndWhenInUseUsageDescription Your background location usage description goes here. NSLocationWhenInUseUsageDescription @@ -43,6 +71,7 @@ UIBackgroundModes + bluetooth-central location UILaunchStoryboardName @@ -66,29 +95,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSPinnedDomains - - api-verified.radar.io - - NSIncludesSubdomains - - NSPinnedLeafIdentities - - - SPKI-SHA256-BASE64 - 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= - - - SPKI-SHA256-BASE64 - 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= - - - - - diff --git a/Example/Example/Utils.swift b/Example/Example/Utils.swift index 8bf3e8f54..10cacca57 100644 --- a/Example/Example/Utils.swift +++ b/Example/Example/Utils.swift @@ -38,6 +38,8 @@ class Utils { return "Exited country \(event.region!.name) (\(event.region!.code)) with \(confidenceStr)" case .conversion: return "Received conversion event with name \(event.conversionName!)" + case .indoorLocation: + return "Received indoor location event with .... TODO TODO TODO" default: return "Unknown" } diff --git a/RadarSDK.xcodeproj/project.pbxproj b/RadarSDK.xcodeproj/project.pbxproj index 485bd9495..8a1ef98c9 100644 --- a/RadarSDK.xcodeproj/project.pbxproj +++ b/RadarSDK.xcodeproj/project.pbxproj @@ -77,6 +77,10 @@ 01F810702AF0119800BD7088 /* RadarVerifiedDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 01F8106F2AF0119800BD7088 /* RadarVerifiedDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 01F99CFB2965C182004E8CF3 /* RadarConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 01F99CFA2965C182004E8CF3 /* RadarConfig.h */; }; 01F99CFD2965C1C4004E8CF3 /* RadarConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F99CFC2965C1C4004E8CF3 /* RadarConfig.m */; }; + 50967A182C517B1D00363728 /* RadarIndoorSurvey.m in Sources */ = {isa = PBXBuildFile; fileRef = 50967A142C517B1D00363728 /* RadarIndoorSurvey.m */; }; + 50967A192C517B1D00363728 /* NSData+GZIP.m in Sources */ = {isa = PBXBuildFile; fileRef = 50967A152C517B1D00363728 /* NSData+GZIP.m */; }; + 50967A1A2C517B1D00363728 /* NSData+GZIP.h in Headers */ = {isa = PBXBuildFile; fileRef = 50967A162C517B1D00363728 /* NSData+GZIP.h */; }; + 50967A1B2C517B1D00363728 /* RadarIndoorSurvey.h in Headers */ = {isa = PBXBuildFile; fileRef = 50967A172C517B1D00363728 /* RadarIndoorSurvey.h */; }; 532FC304277A790600989279 /* Radar+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 532FC303277A783900989279 /* Radar+Internal.h */; }; 53B3B26B23EE41B400080818 /* context.json in Resources */ = {isa = PBXBuildFile; fileRef = 53B3B26A23EE41B400080818 /* context.json */; }; 53CCD783275E579800F79CC8 /* RadarLogBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CCD782275E579800F79CC8 /* RadarLogBuffer.m */; }; @@ -185,6 +189,10 @@ 01F8106F2AF0119800BD7088 /* RadarVerifiedDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RadarVerifiedDelegate.h; sourceTree = ""; }; 01F99CFA2965C182004E8CF3 /* RadarConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RadarConfig.h; sourceTree = ""; }; 01F99CFC2965C1C4004E8CF3 /* RadarConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RadarConfig.m; sourceTree = ""; }; + 50967A142C517B1D00363728 /* RadarIndoorSurvey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RadarIndoorSurvey.m; sourceTree = ""; }; + 50967A152C517B1D00363728 /* NSData+GZIP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+GZIP.m"; sourceTree = ""; }; + 50967A162C517B1D00363728 /* NSData+GZIP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+GZIP.h"; sourceTree = ""; }; + 50967A172C517B1D00363728 /* RadarIndoorSurvey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RadarIndoorSurvey.h; sourceTree = ""; }; 532FC303277A783900989279 /* Radar+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Radar+Internal.h"; sourceTree = ""; }; 5343FFD923E38BA300808D93 /* RadarContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RadarContext.m; sourceTree = ""; }; 53B3B26A23EE41B400080818 /* context.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = context.json; sourceTree = ""; }; @@ -457,6 +465,10 @@ DD236C772308797B00EB88F9 /* RadarSDK */ = { isa = PBXGroup; children = ( + 50967A162C517B1D00363728 /* NSData+GZIP.h */, + 50967A152C517B1D00363728 /* NSData+GZIP.m */, + 50967A172C517B1D00363728 /* RadarIndoorSurvey.h */, + 50967A142C517B1D00363728 /* RadarIndoorSurvey.m */, 825732502B72BE1900DF8B88 /* PrivacyInfo.xcprivacy */, 96A5A0D827AD9F7F007B960B /* Include */, DD236C792308797B00EB88F9 /* Info.plist */, @@ -639,6 +651,7 @@ 01F810702AF0119800BD7088 /* RadarVerifiedDelegate.h in Headers */, 96A5A0CA27AD9F41007B960B /* RadarTrip+Internal.h in Headers */, 96A5A0FF27AD9F7F007B960B /* RadarGeofenceGeometry.h in Headers */, + 50967A1A2C517B1D00363728 /* NSData+GZIP.h in Headers */, 96A5A0CB27AD9F41007B960B /* RadarRoute+Internal.h in Headers */, 96A5A10527AD9F7F007B960B /* RadarTrackingOptions.h in Headers */, 96A5A10927AD9F7F007B960B /* RadarContext.h in Headers */, @@ -651,6 +664,7 @@ 0107AA0F26220047008AB52F /* RadarBeaconManager.h in Headers */, 96A5A0D027AD9F41007B960B /* RadarRouteGeometry+Internal.h in Headers */, 0107AA1626220050008AB52F /* RadarLogger.h in Headers */, + 50967A1B2C517B1D00363728 /* RadarIndoorSurvey.h in Headers */, 0107AA1F26220059008AB52F /* RadarSettings.h in Headers */, 96A5A0C027AD9F41007B960B /* RadarRouteDistance+Internal.h in Headers */, 96A5A0D227AD9F41007B960B /* RadarContext+Internal.h in Headers */, @@ -839,6 +853,7 @@ 0107AB29262201F4008AB52F /* RadarTrackingOptions.m in Sources */, 0107AB2F262201FB008AB52F /* RadarUtils.m in Sources */, 0107AA8926220140008AB52F /* RadarChain.m in Sources */, + 50967A192C517B1D00363728 /* NSData+GZIP.m in Sources */, F667F8272BFBF3C8001F2F67 /* RadarSdkConfiguration.m in Sources */, F667F8272BFBF3C8001F2F67 /* RadarSdkConfiguration.m in Sources */, 0107AB11262201D9008AB52F /* RadarCollectionAdditions.m in Sources */, @@ -868,6 +883,7 @@ 01F99CFD2965C1C4004E8CF3 /* RadarConfig.m in Sources */, 0107AB1A262201E2008AB52F /* RadarLogger.m in Sources */, 019514392BD081630031ABA2 /* RadarVerifiedLocationToken.m in Sources */, + 50967A182C517B1D00363728 /* RadarIndoorSurvey.m in Sources */, 0107AACE2622018A008AB52F /* RadarRouteDuration.m in Sources */, 0107AB17262201DE008AB52F /* RadarDelegateHolder.m in Sources */, ); diff --git a/RadarSDK/Include/Radar.h b/RadarSDK/Include/Radar.h index 7e5904d3f..364fec460 100644 --- a/RadarSDK/Include/Radar.h +++ b/RadarSDK/Include/Radar.h @@ -288,6 +288,9 @@ typedef void (^_Nonnull RadarRouteMatrixCompletionHandler)(RadarStatus status, R */ typedef void (^_Nonnull RadarLogConversionCompletionHandler)(RadarStatus status, RadarEvent *_Nullable event); +// define RadarIndoorsSurveyCompletionHandler -- which is called with no arguments +typedef void (^_Nonnull RadarIndoorsSurveyCompletionHandler)(NSString *_Nullable result); + /** The main class used to interact with the Radar SDK. @@ -1086,6 +1089,12 @@ logConversionWithNotification units:(RadarRouteUnits)units completionHandler:(RadarRouteMatrixCompletionHandler)completionHandler NS_SWIFT_NAME(getMatrix(origins:destinations:mode:units:completionHandler:)); +#pragma mark - Indoors + ++ (void)doIndoorSurvey:(NSString *)placeLabel + forLength:(int)surveyLengthSeconds + completionHandler:(RadarIndoorsSurveyCompletionHandler)completionHandler; + #pragma mark - Logging /** diff --git a/RadarSDK/Include/RadarBeacon.h b/RadarSDK/Include/RadarBeacon.h index 5033c9379..cfb46aa90 100644 --- a/RadarSDK/Include/RadarBeacon.h +++ b/RadarSDK/Include/RadarBeacon.h @@ -69,6 +69,7 @@ NS_ASSUME_NONNULL_BEGIN + (NSArray *_Nullable)arrayForBeacons:(NSArray *_Nullable)beacons; - (NSDictionary *_Nonnull)dictionaryValue; +- (void)setRssi:(NSInteger)rssi; @end diff --git a/RadarSDK/Include/RadarEvent.h b/RadarSDK/Include/RadarEvent.h index 417707f1e..c34139d21 100644 --- a/RadarSDK/Include/RadarEvent.h +++ b/RadarSDK/Include/RadarEvent.h @@ -71,7 +71,9 @@ typedef NS_ENUM(NSInteger, RadarEventType) { /// 'user.arrived_at_wrong_trip_destination` RadarEventTypeUserArrivedAtWrongTripDestination NS_SWIFT_NAME(userArrivedAtWrongTripDestination), /// `user.failed_fraud` - RadarEventTypeUserFailedFraud NS_SWIFT_NAME(userFailedFraud) + RadarEventTypeUserFailedFraud NS_SWIFT_NAME(userFailedFraud), + /// `user.indoor_location` + RadarEventTypeIndoorLocation NS_SWIFT_NAME(indoorLocation) }; /** diff --git a/RadarSDK/Include/RadarTrackingOptions.h b/RadarSDK/Include/RadarTrackingOptions.h index 518adb9b6..27b20bb8f 100644 --- a/RadarSDK/Include/RadarTrackingOptions.h +++ b/RadarSDK/Include/RadarTrackingOptions.h @@ -154,6 +154,8 @@ typedef NS_ENUM(NSInteger, RadarTrackingOptionsSyncLocations) { */ @property (nonatomic, assign) BOOL beacons; +@property (nonatomic, assign) BOOL doIndoorsSurvey; + /** Updates about every 30 seconds while moving or stopped. Moderate battery usage. Shows the flashing blue status bar during tracking. @see https://developer.apple.com/documentation/corelocation/cllocationmanager/2923541-showsbackgroundlocationindicator diff --git a/RadarSDK/NSData+GZIP.h b/RadarSDK/NSData+GZIP.h new file mode 100644 index 000000000..ac6a7886c --- /dev/null +++ b/RadarSDK/NSData+GZIP.h @@ -0,0 +1,43 @@ +// +// GZIP.h +// +// Version 1.3.2 +// +// Created by Nick Lockwood on 03/06/2012. +// Copyright (C) 2012 Charcoal Design +// +// Distributed under the permissive MIT license +// Get the latest version from here: +// +// https://github.com/nicklockwood/GZIP +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#import + + +@interface NSData (GZIP) + +- (nullable NSData *)gzippedDataWithCompressionLevel:(float)level; +- (nullable NSData *)gzippedData; +- (nullable NSData *)gunzippedData; +- (BOOL)isGzippedData; + +@end diff --git a/RadarSDK/NSData+GZIP.m b/RadarSDK/NSData+GZIP.m new file mode 100644 index 000000000..e20a95c6c --- /dev/null +++ b/RadarSDK/NSData+GZIP.m @@ -0,0 +1,135 @@ +// +// GZIP.m +// +// Version 1.3.2 +// +// Created by Nick Lockwood on 03/06/2012. +// Copyright (C) 2012 Charcoal Design +// +// Distributed under the permissive MIT license +// Get the latest version from here: +// +// https://github.com/nicklockwood/GZIP +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#import "NSData+GZIP.h" +#import + + +#pragma clang diagnostic ignored "-Wcast-qual" + + +@implementation NSData (GZIP) + +- (NSData *)gzippedDataWithCompressionLevel:(float)level +{ + if (self.length == 0 || [self isGzippedData]) + { + return self; + } + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = (uint)self.length; + stream.next_in = (Bytef *)(void *)self.bytes; + stream.total_out = 0; + stream.avail_out = 0; + + static const NSUInteger ChunkSize = 16384; + + NSMutableData *output = nil; + int compression = (level < 0.0f)? Z_DEFAULT_COMPRESSION: (int)(roundf(level * 9)); + if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) + { + output = [NSMutableData dataWithLength:ChunkSize]; + while (stream.avail_out == 0) + { + if (stream.total_out >= output.length) + { + output.length += ChunkSize; + } + stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out; + stream.avail_out = (uInt)(output.length - stream.total_out); + deflate(&stream, Z_FINISH); + } + deflateEnd(&stream); + output.length = stream.total_out; + } + + return output; +} + +- (NSData *)gzippedData +{ + return [self gzippedDataWithCompressionLevel:-1.0f]; +} + +- (NSData *)gunzippedData +{ + if (self.length == 0 || ![self isGzippedData]) + { + return self; + } + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.avail_in = (uint)self.length; + stream.next_in = (Bytef *)self.bytes; + stream.total_out = 0; + stream.avail_out = 0; + + NSMutableData *output = nil; + if (inflateInit2(&stream, 47) == Z_OK) + { + int status = Z_OK; + output = [NSMutableData dataWithCapacity:self.length * 2]; + while (status == Z_OK) + { + if (stream.total_out >= output.length) + { + output.length += self.length / 2; + } + stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out; + stream.avail_out = (uInt)(output.length - stream.total_out); + status = inflate (&stream, Z_SYNC_FLUSH); + } + if (inflateEnd(&stream) == Z_OK) + { + if (status == Z_STREAM_END) + { + output.length = stream.total_out; + } + } + } + + return output; +} + +- (BOOL)isGzippedData +{ + const UInt8 *bytes = (const UInt8 *)self.bytes; + return (self.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); +} + +@end diff --git a/RadarSDK/Radar.m b/RadarSDK/Radar.m index 5d9759261..febbb68fb 100644 --- a/RadarSDK/Radar.m +++ b/RadarSDK/Radar.m @@ -13,6 +13,7 @@ #import "RadarConfig.h" #import "RadarCoordinate+Internal.h" #import "RadarDelegateHolder.h" +#import "RadarIndoorSurvey.h" #import "RadarLocationManager.h" #import "RadarLogBuffer.h" #import "RadarLogger.h" @@ -165,6 +166,14 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire return; } + // TODO indoors...?? + // TODO indoors...?? + // TODO indoors...?? + // TODO indoors...?? + // TODO add indoors call / callback logic here?? + // it's similar --- but different?? --- than LocationManager's sendLocation...? + // ALSO it doesn't use/call/care about useRadarModifiedBeacon...? + void (^callTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { [[RadarAPIClient sharedInstance] trackWithLocation:location @@ -173,6 +182,7 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire source:RadarLocationSourceForegroundLocation replayed:NO beacons:beacons + indoorsWhereAmIScan:@"" completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { if (status == RadarStatusSuccess) { @@ -239,6 +249,12 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire } + (void)trackOnceWithLocation:(CLLocation *)location completionHandler:(RadarTrackCompletionHandler)completionHandler { + // TODO do indoors stuff here too...??? + // TODO do indoors stuff here too...??? + // TODO do indoors stuff here too...??? + // TODO do indoors stuff here too...??? + // TODO do indoors stuff here too...??? + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"trackOnce()"]; [[RadarAPIClient sharedInstance] trackWithLocation:location stopped:NO @@ -246,6 +262,7 @@ + (void)trackOnceWithLocation:(CLLocation *)location completionHandler:(RadarTra source:RadarLocationSourceManualLocation replayed:NO beacons:nil + indoorsWhereAmIScan:@"" completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { if (status == RadarStatusSuccess && config != nil) { @@ -354,6 +371,7 @@ + (void)mockTrackingWithOrigin:(CLLocation *)origin source:RadarLocationSourceMockLocation replayed:NO beacons:nil + indoorsWhereAmIScan:@"" completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { if (completionHandler) { @@ -1015,6 +1033,21 @@ + (void)getMatrixFromOrigins:(NSArray *_Nonnull)origins }]; } +#pragma mark - Indoors + ++ (void)doIndoorSurvey:(NSString *)placeLabel + forLength:(int)surveyLengthSeconds + completionHandler:(RadarIndoorsSurveyCompletionHandler)completionHandler { + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"doIndoorsSurvey()"]; + + [[RadarIndoorSurvey sharedInstance] start:placeLabel + forLength:surveyLengthSeconds + withKnownLocation:nil + isWhereAmIScan:NO + withCompletionHandler:completionHandler + ]; +} + #pragma mark - Logging + (void)setLogLevel:(RadarLogLevel)level { diff --git a/RadarSDK/RadarAPIClient.h b/RadarSDK/RadarAPIClient.h index 5cc27b47b..36721b824 100644 --- a/RadarSDK/RadarAPIClient.h +++ b/RadarSDK/RadarAPIClient.h @@ -78,6 +78,7 @@ typedef void (^_Nonnull RadarSyncLogsAPICompletionHandler)(RadarStatus status); source:(RadarLocationSource)source replayed:(BOOL)replayed beacons:(NSArray *_Nullable)beacons + indoorsWhereAmIScan:(NSString *)indoorsWhereAmIScan completionHandler:(RadarTrackAPICompletionHandler _Nonnull)completionHandler; - (void)trackWithLocation:(CLLocation *_Nonnull)location @@ -86,6 +87,7 @@ typedef void (^_Nonnull RadarSyncLogsAPICompletionHandler)(RadarStatus status); source:(RadarLocationSource)source replayed:(BOOL)replayed beacons:(NSArray *_Nullable)beacons + indoorsWhereAmIScan:(NSString *)indoorsWhereAmIScan verified:(BOOL)verified attestationString:(NSString *_Nullable)attestationString keyId:(NSString *_Nullable)keyId diff --git a/RadarSDK/RadarAPIClient.m b/RadarSDK/RadarAPIClient.m index 590b93e9f..bf3b1cf71 100644 --- a/RadarSDK/RadarAPIClient.m +++ b/RadarSDK/RadarAPIClient.m @@ -173,6 +173,7 @@ - (void)trackWithLocation:(CLLocation *_Nonnull)location source:(RadarLocationSource)source replayed:(BOOL)replayed beacons:(NSArray *_Nullable)beacons + indoorsWhereAmIScan:(NSString *)indoorsWhereAmIScan completionHandler:(RadarTrackAPICompletionHandler _Nonnull)completionHandler { [self trackWithLocation:location stopped:stopped @@ -180,6 +181,7 @@ - (void)trackWithLocation:(CLLocation *_Nonnull)location source:source replayed:replayed beacons:beacons + indoorsWhereAmIScan:indoorsWhereAmIScan verified:NO attestationString:nil keyId:nil @@ -194,6 +196,7 @@ - (void)trackWithLocation:(CLLocation *_Nonnull)location source:(RadarLocationSource)source replayed:(BOOL)replayed beacons:(NSArray *_Nullable)beacons + indoorsWhereAmIScan:(NSString *)indoorsWhereAmIScan verified:(BOOL)verified attestationString:(NSString *_Nullable)attestationString keyId:(NSString *_Nullable)keyId @@ -299,6 +302,12 @@ - (void)trackWithLocation:(CLLocation *_Nonnull)location if (beacons) { params[@"beacons"] = [RadarBeacon arrayForBeacons:beacons]; } + + NSLog(@"indoorsWhereAmIScan length: %lu", (unsigned long)indoorsWhereAmIScan.length); + if (indoorsWhereAmIScan) { + params[@"indoorsWhereAmIScan"] = indoorsWhereAmIScan; + } + NSString *locationAuthorization = [RadarUtils locationAuthorization]; if (locationAuthorization) { params[@"locationAuthorization"] = locationAuthorization; diff --git a/RadarSDK/RadarBeacon.m b/RadarSDK/RadarBeacon.m index cc4fff0e8..b2fa8ffd7 100644 --- a/RadarSDK/RadarBeacon.m +++ b/RadarSDK/RadarBeacon.m @@ -232,4 +232,9 @@ - (NSUInteger)hash { return [self.uuid hash] ^ [self.major hash] ^ [self.minor hash]; } +// set rssi +- (void)setRssi:(NSInteger)rssi { + _rssi = rssi; +} + @end diff --git a/RadarSDK/RadarBeaconManager.m b/RadarSDK/RadarBeaconManager.m index d3f940a0e..10695e4a3 100644 --- a/RadarSDK/RadarBeaconManager.m +++ b/RadarSDK/RadarBeaconManager.m @@ -295,6 +295,22 @@ - (void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForReg - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(nonnull NSArray *)beacons inRegion:(nonnull CLBeaconRegion *)region { for (CLBeacon *beacon in beacons) { + + // first, check if this beacon was already in nearbybeacons + // if so, and we have a non 0 rssi, update the rssi + [self.nearbyBeacons enumerateObjectsUsingBlock:^(RadarBeacon * _Nonnull radarBeacon, BOOL * _Nonnull stop) { + if ([radarBeacon.uuid isEqualToString:[beacon.proximityUUID UUIDString]] && [radarBeacon.major isEqualToString:[NSString stringWithFormat:@"%@", beacon.major]] && [radarBeacon.minor isEqualToString:[NSString stringWithFormat:@"%@", beacon.minor]]) { + // log "same beacon" + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"same beacon!"]; + if (beacon.rssi != 0 && beacon.rssi != radarBeacon.rssi) { + // OVERWRITING STALE RSSI!!!! + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Overwriting stale RSSI: %ld", (long)radarBeacon.rssi]]; + [radarBeacon setRssi:beacon.rssi]; + } + *stop = YES; + } + }]; + [self.nearbyBeaconIdentifiers addObject:region.identifier]; [self.nearbyBeacons addObject:[RadarBeacon fromCLBeacon:beacon]]; diff --git a/RadarSDK/RadarEvent.m b/RadarSDK/RadarEvent.m index 572aa728f..1fecddf78 100644 --- a/RadarSDK/RadarEvent.m +++ b/RadarSDK/RadarEvent.m @@ -182,6 +182,8 @@ - (instancetype _Nullable)initWithObject:(id)object { type = RadarEventTypeUserArrivedAtWrongTripDestination; } else if ([typeStr isEqualToString:@"user.failed_fraud"]) { type = RadarEventTypeUserFailedFraud; + } else if ([typeStr isEqualToString:@"indoors.location"]) { + type = RadarEventTypeIndoorLocation; } else { type = RadarEventTypeConversion; conversionName = typeStr; @@ -296,8 +298,16 @@ - (instancetype _Nullable)initWithObject:(id)object { float locationCoordinatesLatitudeFloat = [locationCoordinatesLatitudeNumber floatValue]; id locationAccuracyObj = dict[@"locationAccuracy"]; - if (locationAccuracyObj && [locationAccuracyObj isKindOfClass:[NSNumber class]]) { - NSNumber *locationAccuracyNumber = (NSNumber *)locationAccuracyObj; + // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? + // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? + // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? + // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? + // if (locationAccuracyObj && [locationAccuracyObj isKindOfClass:[NSNumber class]]) { + if (YES) { + // FIXMED + // FIXMED + // NSNumber *locationAccuracyNumber = (NSNumber *)locationAccuracyObj; + NSNumber *locationAccuracyNumber = [NSNumber numberWithFloat:123.0]; location = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(locationCoordinatesLatitudeFloat, locationCoordinatesLongitudeFloat) altitude:-1 @@ -395,6 +405,8 @@ + (NSString *)stringForType:(RadarEventType)type { return @"user.failed_fraud"; case RadarEventTypeConversion: return @"custom"; + case RadarEventTypeIndoorLocation: + return @"indoors.location"; default: return @"unknown"; } diff --git a/RadarSDK/RadarIndoorSurvey.h b/RadarSDK/RadarIndoorSurvey.h new file mode 100644 index 000000000..06de19d55 --- /dev/null +++ b/RadarSDK/RadarIndoorSurvey.h @@ -0,0 +1,35 @@ +#import +#import + +#import "Radar.h" +#import "RadarUtils.h" + +@interface RadarIndoorSurvey : NSObject + +@property (nonatomic, strong) CBCentralManager *centralManager; +// also store a CMMotionManager property +@property (nonatomic, strong) CMMotionManager *motionManager; +@property (nonatomic, strong) NSString *placeLabel; +@property (nonatomic, copy) RadarIndoorsSurveyCompletionHandler completionHandler; +@property (nonatomic, strong) NSMutableArray *bluetoothReadings; +// add a scanid uuid property to the class +@property (nonatomic, strong) NSString *scanId; +// add a locationAtTimeOfSurveyStart CLLocation property to the class +@property (nonatomic, strong) CLLocation *locationAtTimeOfSurveyStart; +// store last received magnet data +@property (nonatomic, strong) CMMagnetometerData *lastMagnetometerData; +// store whether this is a whereAmI scan +@property (nonatomic) BOOL isWhereAmIScan; +// store whether we are scannig +@property (nonatomic) BOOL isScanning; + +#define WHERE_AM_I_DURATION_SECONDS 10 + ++ (instancetype)sharedInstance; + +- (void)start:(NSString *)placeLabel forLength:(int)surveyLengthSeconds withKnownLocation:(CLLocation *)knownLocation isWhereAmIScan:(BOOL)isWhereAmIScan withCompletionHandler:(RadarIndoorsSurveyCompletionHandler)completionHandler; +- (void)startScanning; +- (void)stopScanning; +- (void)kickOffMotionAndBluetooth:(int)surveyLengthSeconds; + +@end diff --git a/RadarSDK/RadarIndoorSurvey.m b/RadarSDK/RadarIndoorSurvey.m new file mode 100644 index 000000000..6a7c6bfcf --- /dev/null +++ b/RadarSDK/RadarIndoorSurvey.m @@ -0,0 +1,351 @@ +#import "RadarIndoorSurvey.h" +#import "NSData+GZIP.h" +#import "RadarUtils.h" +#import "RadarLogger.h" +#import "RadarLocationManager.h" + +@implementation RadarIndoorSurvey + ++ (instancetype)sharedInstance { + static dispatch_once_t once; + static id sharedInstance; + dispatch_once(&once, ^{ + sharedInstance = [self new]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + self.isScanning = NO; + self.isWhereAmIScan = NO; + } + return self; +} + +// return instance's isScanning +- (BOOL)isScanning { + return _isScanning; +} + +// return instance's isWhereAmIScan +- (BOOL)isWhereAmIScan { + return _isWhereAmIScan; +} + + +- (void)start:(NSString *)placeLabel forLength:(int)surveyLengthSeconds withKnownLocation:(CLLocation *)knownLocation isWhereAmIScan:(BOOL)isWhereAmIScan withCompletionHandler:(RadarIndoorsSurveyCompletionHandler)completionHandler { + // convert to [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:message]; call + // NSLog(@"start called with placeLabel: %@, surveyLengthSeconds: %d, isWhereAmIScan: %d", placeLabel, surveyLengthSeconds, isWhereAmIScan); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"RadarIndoorSurvey start called with placeLabel: %@, surveyLengthSeconds: %d, isWhereAmIScan: %d", placeLabel, surveyLengthSeconds, isWhereAmIScan]]; + + // log self.isScanning + // NSLog(@"self.isScanning: %d", self.isScanning); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"self.isScanning: %d", self.isScanning]]; + + if(self.isScanning) { + // NSLog(@"Error: start called while already scanning"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelError message:@"Error: start called while already scanning"]; + + // call callback, pass bad data + completionHandler(@"Error: start called while already scanning"); + + return; + } + + self.isScanning = YES; + + self.placeLabel = placeLabel; + self.completionHandler = completionHandler; + self.bluetoothReadings = [NSMutableArray new]; + + self.isWhereAmIScan = isWhereAmIScan; + + // set fresh uuid on self.scanId + self.scanId = [[NSUUID UUID] UUIDString]; + + // if isWhereAmIScan but no knownLocation, throw error + // as we are expecting to have been called from track + if (isWhereAmIScan && !knownLocation) { + // convert to [[RadarLogger sharedInstance] + // NSLog(@"Error: start called with isWhereAmIScan but no knownLocation"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelError message:@"Error: start called with isWhereAmIScan but no knownLocation"]; + completionHandler(@"Error: start called with isWhereAmIScan but no knownLocation"); + self.isScanning = NO; + return; + } else if(isWhereAmIScan && knownLocation) { + // if isWhereAmIScan and knownLocation, + // set self.locationAtTimeOfSurveyStart to knownLocation + self.locationAtTimeOfSurveyStart = knownLocation; + + [self kickOffMotionAndBluetooth:surveyLengthSeconds]; + } else if(!isWhereAmIScan) { + // get location at time of survey start + + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"calling RadarLocationManager getLocationWithDesiredAccuracy"]; + [[RadarLocationManager sharedInstance] + getLocationWithDesiredAccuracy:RadarTrackingOptionsDesiredAccuracyMedium + completionHandler:^(RadarStatus status, CLLocation *_Nullable location, BOOL stopped) { + if (status != RadarStatusSuccess) { + return; + } + + // NSLog(@"location: %f, %f", location.coordinate.latitude, location.coordinate.longitude); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"location: %f, %f", location.coordinate.latitude, location.coordinate.longitude]]; + // print location object as is + // NSLog(@"%@", location); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"%@", location]]; + + // set self.locationAtTimeOfSurveyStart to location + self.locationAtTimeOfSurveyStart = location; + + [self kickOffMotionAndBluetooth:surveyLengthSeconds]; + }]; + } +} + +- (void)kickOffMotionAndBluetooth:(int)surveyLengthSeconds { + // NSLog(@"kicking off CMMotionManager"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"kicking off CMMotionManager"]; + self.motionManager = [[CMMotionManager alloc] init]; + // motionManager.startMagnetometerUpdates(to: OperationQueue.main, withHandler: updateMotionManagerHandler!) + [self.motionManager startMagnetometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMagnetometerData *magnetometerData, NSError *error) { + if (error) { + // NSLog(@"startMagnetometerUpdatesToQueue error: %@", error); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelError message:[NSString stringWithFormat:@"startMagnetometerUpdatesToQueue error: %@", error]]; + } else { + self.lastMagnetometerData = magnetometerData; + } + }]; + + // NSLog(@"kicking off CBCentralManager"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"kicking off CBCentralManager"]; + // print time + // NSLog(@"time: %f", [[NSDate date] timeIntervalSince1970]); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"time: %f", [[NSDate date] timeIntervalSince1970]]]; + + // kick off the survey by init'ing the corebluetooth manager + self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; + [NSTimer scheduledTimerWithTimeInterval:surveyLengthSeconds target:self selector:@selector(stopScanning) userInfo:nil repeats:NO]; +} + +- (void)startScanning { + // NSLog(@"startScanning called --- calling scanForPeripheralsWithServices"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"startScanning called --- calling scanForPeripheralsWithServices"]; + [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @YES}]; +} + +- (void)stopScanning { + // NSLog(@"stopScanning called"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"stopScanning called"]; + // NSLog(@"time: %f", [[NSDate date] timeIntervalSince1970]); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"time: %f", [[NSDate date] timeIntervalSince1970]]]; + + [self.centralManager stopScan]; + + // do a track once call to force the OS to give us a fresh location, and include that as part of the payload (include it in every line) + // also create a unique scanid value that will be added to every line + + // join all self.bluetoothReadings with newlines and POST to server + NSString *payload = [self.bluetoothReadings componentsJoinedByString:@"\n"]; + + // if [RadarUtils isSimulator] , put fake data into payload + + // NSLog(@"[RadarUtils isSimulator]: %d", [RadarUtils isSimulator]); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"[RadarUtils isSimulator]: %d", [RadarUtils isSimulator]]]; + + if ([RadarUtils isSimulator]) { + payload = @"?time=1716583686.556668&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=C9AC95A0-D6B5-D57F-014B-0FDD11D51E7E&peripheral.name=(no%20name)&rssi=-88&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.559950&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=540803B9-86A3-CF2E-2A4B-1B23C6DB0214&peripheral.name=%5BTV%5D%20Samsung%209%20Series%20(86)&rssi=-71&manufacturerId=7500&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.560602&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=540803B9-86A3-CF2E-2A4B-1B23C6DB0214&peripheral.name=%5BTV%5D%20Samsung%209%20Series%20(86)&rssi=-71&manufacturerId=7500&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.563503&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=E25D13C2-08A0-9598-327A-CC4B2F782E53&peripheral.name=(no%20name)&rssi=-70&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.568083&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=0B9BD1B0-D482-31D2-B723-882E5AD9FCEA&peripheral.name=(no%20name)&rssi=-88&manufacturerId=0600&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.572948&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=D48D165B-FE69-C705-6B14-4000822C5EC7&peripheral.name=(no%20name)&rssi=-78&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.573204&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=D48D165B-FE69-C705-6B14-4000822C5EC7&peripheral.name=(no%20name)&rssi=-78&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.573577&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=E6FD4D8E-6C80-EACC-6B93-9DDB8D9AAAA5&peripheral.name=(no%20name)&rssi=-73&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.590971&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=571CE11A-F8BE-43AC-460C-C1A9FA3F0406&peripheral.name=(no%20name)&rssi=-64&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-29.425323&magnetometer.field.y=-112.600601&magnetometer.field.z=-246.101929&magnetometer.timestamp=65614.520519&magnetometer.field.magnitude=272.233180\n"; + } + + // print length of payload + // NSLog(@"payload length: %lu", (unsigned long)[payload length]); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"payload length: %lu", (unsigned long)[payload length]]]; + + // compress payload and base64 encode it + + // compress payload + NSData *compressedData = [payload dataUsingEncoding:NSUTF8StringEncoding]; + NSData *compressedDataGzipped = [compressedData gzippedData]; + // print length of compressed payload + // NSLog(@"compressedDataGzipped length: %lu", (unsigned long)[compressedDataGzipped length]); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"compressedDataGzipped length: %lu", (unsigned long)[compressedDataGzipped length]]]; + + // base64 encode + NSString *compressedDataGzippedBase64 = [compressedDataGzipped base64EncodedStringWithOptions:0]; + + // print length of base64 encoded payload + // NSLog(@"compressedDataGzippedBase64 length: %lu", (unsigned long)[compressedDataGzippedBase64 length]); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"compressedDataGzippedBase64 length: %lu", (unsigned long)[compressedDataGzippedBase64 length]]]; + + // NSLog(@"self.isWhereAmIScan %d", self.isWhereAmIScan); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"self.isWhereAmIScan %d", self.isWhereAmIScan]]; + + // if self.isWhereAmIScan, call callback with the payload string + if (self.isWhereAmIScan) { + if (self.completionHandler) { + self.completionHandler(compressedDataGzippedBase64); + } + } else { + // this is a survey scan i.e. we are sending data back to the + // ML server for training purposes + + // POST payload + // TODO move to prod server..? + // FIXME not working right now + // FIXME not working right now + // FIXME not working right now + // FIXME not working right now + // FIXME not working right now + // FIXME not working right now + // FIXME not working right now + // FIXME not working right now + NSURL *url = [NSURL URLWithString:@"https://ml-prod.radarindoors.com/scan_results"]; + + NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url]; + [urlRequest setHTTPMethod:@"POST"]; + [urlRequest setHTTPBody:[compressedDataGzippedBase64 dataUsingEncoding:NSUTF8StringEncoding]]; + [urlRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if (data && self.completionHandler) { + // decode data to string + NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + // NSLog(@"responseString: %@", responseString); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"responseString: %@", responseString]]; + self.completionHandler(responseString); + } + }]; + [task resume]; + } + + // NSLog(@"callign removeAllObjects, clearing scanId, etc."); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"callign removeAllObjects, clearing scanId, etc."]; + + // removeAllObjects from bluetooth readings i.e. clear array + [self.bluetoothReadings removeAllObjects]; + // reset self.scanId + self.scanId = nil; + // reset self.locationAtTimeOfSurveyStart + self.locationAtTimeOfSurveyStart = nil; + // reset self.lastMagnetometerData + self.lastMagnetometerData = nil; + + // NSLog(@"stopScanning end"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"stopScanning end"]; + + // set self.isScanning to NO + self.isScanning = NO; +} + +- (void)centralManagerDidUpdateState:(CBCentralManager *)central { + switch (central.state) { + case CBManagerStatePoweredOff: + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"CBCentralManager: Is Powered Off."]; + break; + case CBManagerStatePoweredOn: + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"CBCentralManager: Is Powered On."]; + // print time + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"time: %f", [[NSDate date] timeIntervalSince1970]]]; + [self startScanning]; + break; + case CBManagerStateUnsupported: + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"CBCentralManager: Is Unsupported."]; + break; + case CBManagerStateUnauthorized: + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"CBCentralManager: Is Unauthorized."]; + break; + case CBManagerStateUnknown: + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"CBCentralManager: Unknown"]; + break; + case CBManagerStateResetting: + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"CBCentralManager: Resetting"]; + break; + default: + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"CBCentralManager: Error"]; + break; + } +} + +- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { + NSString *manufacturerId = @""; + NSData *manufacturerData = advertisementData[@"kCBAdvDataManufacturerData"]; + if (manufacturerData) { + manufacturerId = [NSString stringWithFormat:@"%04X", (UInt16)((((uint8_t *)manufacturerData.bytes)[0] + ((uint8_t *)manufacturerData.bytes)[1]) << 8)]; + } + + NSString *name = peripheral.name ?: @"(no name)"; + + NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970]; + + // extract kCBAdvDataServiceUUIDs from advertisement data if it's available + NSArray *serviceUUIDs = advertisementData[@"kCBAdvDataServiceUUIDs"]; + // join service uuids into string or store "(no services)" if array is empty/nil + NSString *serviceUUIDsString = serviceUUIDs ? [serviceUUIDs componentsJoinedByString:@","] : @"(no services)"; + + // extract kCBAdvDataIsConnectable from advertisement data if it's available + NSNumber *isConnectable = advertisementData[@"kCBAdvDataIsConnectable"]; + + // extract kCBAdvDataTxPowerLevel from advertisement data if it's available + NSNumber *txPowerLevel = advertisementData[@"kCBAdvDataTxPowerLevel"]; + + NSURLComponents *components = [NSURLComponents componentsWithString: @""]; + NSMutableArray *queryItems = [NSMutableArray arrayWithArray:@[ + [NSURLQueryItem queryItemWithName:@"time" value:[NSString stringWithFormat:@"%f", timestamp]], + [NSURLQueryItem queryItemWithName:@"label" value:self.placeLabel], + [NSURLQueryItem queryItemWithName:@"peripheral.identifier" value:[peripheral.identifier UUIDString]], + [NSURLQueryItem queryItemWithName:@"peripheral.name" value:name], + [NSURLQueryItem queryItemWithName:@"rssi" value:[RSSI stringValue]], + [NSURLQueryItem queryItemWithName:@"manufacturerId" value:manufacturerId], + [NSURLQueryItem queryItemWithName:@"scanId" value:self.scanId], + [NSURLQueryItem queryItemWithName:@"serviceUUIDs" value:serviceUUIDsString], + + [NSURLQueryItem queryItemWithName:@"location.coordinate.latitude" value:[NSString stringWithFormat:@"%f", self.locationAtTimeOfSurveyStart.coordinate.latitude]], + [NSURLQueryItem queryItemWithName:@"location.coordinate.longitude" value:[NSString stringWithFormat:@"%f", self.locationAtTimeOfSurveyStart.coordinate.longitude]], + [NSURLQueryItem queryItemWithName:@"location.horizontalAccuracy" value:[NSString stringWithFormat:@"%f", self.locationAtTimeOfSurveyStart.horizontalAccuracy]], + [NSURLQueryItem queryItemWithName:@"location.verticalAccuracy" value:[NSString stringWithFormat:@"%f", self.locationAtTimeOfSurveyStart.verticalAccuracy]], + [NSURLQueryItem queryItemWithName:@"location.altitude" value:[NSString stringWithFormat:@"%f", self.locationAtTimeOfSurveyStart.altitude]], + [NSURLQueryItem queryItemWithName:@"location.timestamp" value:[NSString stringWithFormat:@"%@", self.locationAtTimeOfSurveyStart.timestamp]], + [NSURLQueryItem queryItemWithName:@"location.floor" value:[NSString stringWithFormat:@"%@", + self.locationAtTimeOfSurveyStart.floor ? self.locationAtTimeOfSurveyStart.floor : @0 + ]], + + [NSURLQueryItem queryItemWithName:@"sdkVersion" value:[RadarUtils sdkVersion]], + [NSURLQueryItem queryItemWithName:@"deviceType" value:[RadarUtils deviceType]], + [NSURLQueryItem queryItemWithName:@"deviceMake" value:[RadarUtils deviceMake]], + [NSURLQueryItem queryItemWithName:@"deviceModel" value:[RadarUtils deviceModel]], + [NSURLQueryItem queryItemWithName:@"deviceOS" value:[RadarUtils deviceOS]], + + // inject x, y, z from self.lastMagnetometerData + // and add sqrt(pow(magnet.field.x, 2) + pow(magnet.field.y, 2) + pow(magnet.field.z, 2)) as well + [NSURLQueryItem queryItemWithName:@"magnetometer.field.x" value:[NSString stringWithFormat:@"%f", self.lastMagnetometerData.magneticField.x]], + [NSURLQueryItem queryItemWithName:@"magnetometer.field.y" value:[NSString stringWithFormat:@"%f", self.lastMagnetometerData.magneticField.y]], + [NSURLQueryItem queryItemWithName:@"magnetometer.field.z" value:[NSString stringWithFormat:@"%f", self.lastMagnetometerData.magneticField.z]], + [NSURLQueryItem queryItemWithName:@"magnetometer.timestamp" value:[NSString stringWithFormat:@"%f", self.lastMagnetometerData.timestamp]], + [NSURLQueryItem queryItemWithName:@"magnetometer.field.magnitude" value:[NSString stringWithFormat:@"%f", sqrt(pow(self.lastMagnetometerData.magneticField.x, 2) + pow(self.lastMagnetometerData.magneticField.y, 2) + pow(self.lastMagnetometerData.magneticField.z, 2))]], + + // inject isConnectable + [NSURLQueryItem queryItemWithName:@"isConnectable" value:[isConnectable stringValue]], + // inject txPowerLevel + [NSURLQueryItem queryItemWithName:@"txPowerLevel" value:[txPowerLevel stringValue]] + ]]; + + if (@available(iOS 15, *)) { + // add ellipsoidalAltitude to queryItems on ios15 only + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"location.ellipsoidalAltitude" value:[NSString stringWithFormat:@"%f", self.locationAtTimeOfSurveyStart.ellipsoidalAltitude]]]; + } + + components.queryItems = queryItems; + NSURL *dataUrl = components.URL; + // stringify dataurl + NSString *queryString = [dataUrl absoluteString]; + [self.bluetoothReadings addObject:queryString]; +} + +- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { + // NSLog(@"centralManager didConnectPeripheral, calling stopScanning"); + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"centralManager didConnectPeripheral, calling stopScanning"]; + [self stopScanning]; +} + +@end diff --git a/RadarSDK/RadarLocationManager.m b/RadarSDK/RadarLocationManager.m index aa63e5d78..c46d84a57 100644 --- a/RadarSDK/RadarLocationManager.m +++ b/RadarSDK/RadarLocationManager.m @@ -13,6 +13,7 @@ #import "RadarBeaconManager.h" #import "RadarCircleGeometry.h" #import "RadarDelegateHolder.h" +#import "RadarIndoorSurvey.h" #import "RadarLocationManager.h" #import "RadarLogger.h" #import "RadarMeta.h" @@ -388,7 +389,9 @@ - (void)updateTracking:(CLLocation *)location fromInitialize:(BOOL)fromInitializ } if (!options.beacons) { [self removeSyncedBeacons]; - } + } + + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"options.doIndoorsSurvey = %d", options.doIndoorsSurvey]]; } else { [self stopUpdates]; [self removeAllRegions]; @@ -701,12 +704,44 @@ - (void)handleLocation:(CLLocation *)location source:(RadarLocationSource)source return; } + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug + message:[NSString stringWithFormat:@"RadarIndoorSurvey sharedInstance isScanning: %d", [[RadarIndoorSurvey sharedInstance] isScanning]]]; + + if([[RadarIndoorSurvey sharedInstance] isScanning]) { + if(![[RadarIndoorSurvey sharedInstance] isWhereAmIScan]) { + // we _are_ currently scanning, but we are not in the "where am i" mode i.e. + // we are surveying! in this case, getLocationWithDesiredAccuracy was called + // which led to (this) handleLocation being called. + // return the location we just got to the completion handler. + + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug + message:[NSString stringWithFormat:@"Indoor surveying, returning location to completion handler | source = %@; location = %@", [Radar stringForLocationSource:source], location]]; + + [self callCompletionHandlersWithStatus:RadarStatusSuccess location:location]; + } + + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug + message:[NSString stringWithFormat:@"Cannot initiate scan while scanning, caching current location | source = %@; location = %@", [Radar stringForLocationSource:source], location]]; + + [self callCompletionHandlersWithStatus:RadarStatusErrorLocation location:nil]; + + return; + } + RadarTrackingOptions *options = [Radar getTrackingOptions]; BOOL wasStopped = [RadarState stopped]; BOOL stopped = NO; BOOL force = (source == RadarLocationSourceForegroundLocation || source == RadarLocationSourceManualLocation || source == RadarLocationSourceBeaconEnter || source == RadarLocationSourceBeaconExit || source == RadarLocationSourceVisitArrival); + + // FIXME indoors --- don't do this.......>??? + // FIXME indoors --- don't do this.......>??? + // FIXME indoors --- don't do this.......>??? + // FIXME indoors --- don't do this.......>??? + // FIXME -- make sure to not skip location because of inaccurate...?? + force = true; + if (wasStopped && !force && location.horizontalAccuracy >= 1000 && options.desiredAccuracy != RadarTrackingOptionsDesiredAccuracyLow) { [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Skipping location: inaccurate | accuracy = %f", location.horizontalAccuracy]]; @@ -855,21 +890,26 @@ - (void)handleLocation:(CLLocation *)location source:(RadarLocationSource)source - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarLocationSource)source replayed:(BOOL)replayed beacons:(NSArray *_Nullable)beacons { [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug - message:[NSString stringWithFormat:@"Sending location | source = %@; location = %@; stopped = %d; replayed = %d; beacons = %@", + message:[NSString stringWithFormat:@"sendLocation | source = %@; location = %@; stopped = %d; replayed = %d; beacons = %@", [Radar stringForLocationSource:source], location, stopped, replayed, beacons]]; self.sending = YES; RadarTrackingOptions *options = [Radar getTrackingOptions]; + // log RadarSettings useRadarModifiedBeacon + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug + message:[NSString stringWithFormat:@"useRadarModifiedBeacon = %d", [RadarSettings useRadarModifiedBeacon]]]; + if ([RadarSettings useRadarModifiedBeacon]) { - void (^callTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { + void (^callTrackAPI)(NSArray *_Nullable, NSString *_Nullable) = ^(NSArray *_Nullable beacons, NSString *_Nullable indoorsWhereAmIScan) { [[RadarAPIClient sharedInstance] trackWithLocation:location stopped:stopped foreground:[RadarUtils foreground] source:source replayed:replayed beacons:beacons + indoorsWhereAmIScan:indoorsWhereAmIScan completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { self.sending = NO; @@ -878,6 +918,32 @@ - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarL [self replaceSyncedGeofences:nearbyGeofences]; }]; }; + + // callback used below, after (possibly) fetching beacons and ranging on them. + // at this point, we have beacons but have not yet done the indoor survey, which we might do or not (based on RTO options) + void (^maybeIndoorSurveyThenCallTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { + // FIXME + // FIXME + // FIXME + if(true || options.doIndoorsSurvey) { + // do indoor survey, then call track api with the beacons and the indoor survey + [[RadarIndoorSurvey sharedInstance] start:@"WHEREAMI" + forLength:WHERE_AM_I_DURATION_SECONDS + withKnownLocation:location + isWhereAmIScan:YES + withCompletionHandler:^(NSString *_Nullable indoorsWhereAmIScan) { + + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug + message:[NSString stringWithFormat:@"received indoor start indoorsWhereAmIScan: %lu", (unsigned long)indoorsWhereAmIScan.length]]; + + callTrackAPI(beacons, indoorsWhereAmIScan); + }]; + + } else { + // no indoor survey -- just call track api with the given beacons + callTrackAPI(beacons, nil); + } + }; if (options.beacons && source != RadarLocationSourceBeaconEnter && @@ -898,11 +964,11 @@ - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarL [[RadarBeaconManager sharedInstance] rangeBeaconUUIDs:beaconUUIDs completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { if (status != RadarStatusSuccess || !beacons) { - callTrackAPI(nil); + maybeIndoorSurveyThenCallTrackAPI(nil); return; } - callTrackAPI(beacons); + maybeIndoorSurveyThenCallTrackAPI(beacons); }]; }]; } else if (beacons && beacons.count) { @@ -911,20 +977,20 @@ - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarL [[RadarBeaconManager sharedInstance] rangeBeacons:beacons completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { if (status != RadarStatusSuccess || !beacons) { - callTrackAPI(nil); + maybeIndoorSurveyThenCallTrackAPI(nil); return; } - callTrackAPI(beacons); + maybeIndoorSurveyThenCallTrackAPI(beacons); }]; }]; } else { - callTrackAPI(@[]); + maybeIndoorSurveyThenCallTrackAPI(@[]); } }]; } else { - callTrackAPI(nil); + maybeIndoorSurveyThenCallTrackAPI(nil); } } else { if (options.beacons) { @@ -952,6 +1018,7 @@ - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarL source:source replayed:replayed beacons:beacons + indoorsWhereAmIScan:@"" completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { self.sending = NO; diff --git a/RadarSDK/RadarLogger.m b/RadarSDK/RadarLogger.m index b5cab0913..65d4e21de 100644 --- a/RadarSDK/RadarLogger.m +++ b/RadarSDK/RadarLogger.m @@ -49,12 +49,19 @@ - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSStr } - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSString *)message includeDate:(BOOL)includeDate includeBattery:(BOOL)includeBattery append:(BOOL)append{ - RadarLogLevel logLevel = [RadarSettings logLevel]; - if (level > logLevel) { - return; - } + // RadarLogLevel logLevel = [RadarSettings logLevel]; + // if (level > logLevel) { + // return; + // } + + // NSString *dateString = [self.dateFormatter stringFromDate:[NSDate date]]; + includeDate = YES; + + // make date string that includes date, second and millisecond + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; + NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; - NSString *dateString = [self.dateFormatter stringFromDate:[NSDate date]]; float batteryLevel = [self.device batteryLevel]; if (includeDate && includeBattery) { message = [NSString stringWithFormat:@"%@ | at %@ | with %2.f%% battery", message, dateString, batteryLevel*100]; @@ -63,6 +70,19 @@ - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSStr } else if (includeBattery) { message = [NSString stringWithFormat:@"%@ | with %2.f%% battery", message, batteryLevel*100]; } + + // ping own (indoors-related) log server for immediate prod remote logging + NSURL *url = [NSURL URLWithString:@"https://logs.radarindoors.com"]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.HTTPMethod = @"POST"; + [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + + NSDictionary *body = @{@"log": message, @"timestamp": dateString}; + NSData *data = [NSJSONSerialization dataWithJSONObject:body options:0 error:nil]; + request.HTTPBody = data; + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request]; + [task resume]; + if (append) { [[RadarLogBuffer sharedInstance] write:level type:type message:message forcePersist:YES]; } else { diff --git a/RadarSDK/RadarSdkConfiguration.m b/RadarSDK/RadarSdkConfiguration.m index b7cf3c0b8..c04031d97 100644 --- a/RadarSDK/RadarSdkConfiguration.m +++ b/RadarSDK/RadarSdkConfiguration.m @@ -9,6 +9,7 @@ #include "Radar.h" #import "RadarLog.h" +#import "RadarLogger.h" #import "RadarUtils.h" #import "RadarAPIClient.h" #import "RadarSettings.h" @@ -16,6 +17,9 @@ @implementation RadarSdkConfiguration - (instancetype)initWithDict:(NSDictionary *)dict { + // log the dict + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"RadarSdkConfiguration initWithDict: %@", dict]]; + self = [super init]; if (self == nil) { return nil; @@ -58,8 +62,13 @@ - (instancetype)initWithDict:(NSDictionary *)dict { } NSObject *useRadarModifiedBeaconObj = dict[@"useRadarModifiedBeacon"]; + // log useRadarModifiedBeaconObj + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"useRadarModifiedBeaconObj: %@", useRadarModifiedBeaconObj]]; + _useRadarModifiedBeacon = NO; if (useRadarModifiedBeaconObj && [useRadarModifiedBeaconObj isKindOfClass:[NSNumber class]]) { + // log "setting _useRadarModifiedBeacon!!" + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"setting _useRadarModifiedBeacon!!"]; _useRadarModifiedBeacon = [(NSNumber *)useRadarModifiedBeaconObj boolValue]; } diff --git a/RadarSDK/RadarSettings.m b/RadarSDK/RadarSettings.m index 190b3bb89..9bbbe1d31 100644 --- a/RadarSDK/RadarSettings.m +++ b/RadarSDK/RadarSettings.m @@ -39,7 +39,9 @@ @implementation RadarSettings static NSString *const kLogLevel = @"radar-logLevel"; static NSString *const kBeaconUUIDs = @"radar-beaconUUIDs"; static NSString *const kHost = @"radar-host"; -static NSString *const kDefaultHost = @"https://api.radar.io"; +// static NSString *const kDefaultHost = @"https://api.radar.io"; +// static NSString *const kDefaultHost = @"https://api.radar-staging.com"; +static NSString *const kDefaultHost = @"https://radar-server-dev-greg.ngrok.io"; static NSString *const kLastTrackedTime = @"radar-lastTrackedTime"; static NSString *const kVerifiedHost = @"radar-verifiedHost"; static NSString *const kDefaultVerifiedHost = @"https://api-verified.radar.io"; diff --git a/RadarSDK/RadarTrackingOptions.m b/RadarSDK/RadarTrackingOptions.m index a1eb69861..5688824eb 100644 --- a/RadarSDK/RadarTrackingOptions.m +++ b/RadarSDK/RadarTrackingOptions.m @@ -29,6 +29,7 @@ @implementation RadarTrackingOptions NSString *const kUseVisits = @"useVisits"; NSString *const kUseSignificantLocationChanges = @"useSignificantLocationChanges"; NSString *const kBeacons = @"beacons"; +NSString *const kDoIndoorsSurvey = @"doIndoorsSurvey"; NSString *const kDesiredAccuracyHigh = @"high"; NSString *const kDesiredAccuracyMedium = @"medium"; @@ -46,7 +47,7 @@ + (RadarTrackingOptions *)presetContinuous { RadarTrackingOptions *options = [RadarTrackingOptions new]; options.desiredStoppedUpdateInterval = 30; options.desiredMovingUpdateInterval = 30; - options.desiredSyncInterval = 20; + options.desiredSyncInterval = 10; options.desiredAccuracy = RadarTrackingOptionsDesiredAccuracyHigh; options.stopDuration = 140; options.stopDistance = 70; @@ -63,6 +64,7 @@ + (RadarTrackingOptions *)presetContinuous { options.useVisits = NO; options.useSignificantLocationChanges = NO; options.beacons = NO; + options.doIndoorsSurvey = NO; return options; } @@ -87,6 +89,7 @@ + (RadarTrackingOptions *)presetResponsive { options.useVisits = YES; options.useSignificantLocationChanges = YES; options.beacons = NO; + options.doIndoorsSurvey = NO; return options; } @@ -111,6 +114,7 @@ + (RadarTrackingOptions *)presetEfficient { options.useVisits = YES; options.useSignificantLocationChanges = NO; options.beacons = NO; + options.doIndoorsSurvey = NO; return options; } @@ -239,6 +243,7 @@ + (RadarTrackingOptions *)trackingOptionsFromDictionary:(NSDictionary *)dict { options.useVisits = [dict[kUseVisits] boolValue]; options.useSignificantLocationChanges = [dict[kUseSignificantLocationChanges] boolValue]; options.beacons = [dict[kBeacons] boolValue]; + options.doIndoorsSurvey = [dict[kDoIndoorsSurvey] boolValue]; return options; } @@ -271,6 +276,7 @@ - (NSDictionary *)dictionaryValue { dict[kUseVisits] = @(self.useVisits); dict[kUseSignificantLocationChanges] = @(self.useSignificantLocationChanges); dict[kBeacons] = @(self.beacons); + dict[kDoIndoorsSurvey] = @(self.doIndoorsSurvey); return dict; } @@ -299,7 +305,7 @@ - (BOOL)isEqual:(id)object { self.syncLocations == options.syncLocations && self.replay == options.replay && self.showBlueBar == options.showBlueBar && self.useStoppedGeofence == options.useStoppedGeofence && self.stoppedGeofenceRadius == options.stoppedGeofenceRadius && self.useMovingGeofence == options.useMovingGeofence && self.movingGeofenceRadius == options.movingGeofenceRadius && self.syncGeofences == options.syncGeofences && - self.useVisits == options.useVisits && self.useSignificantLocationChanges == options.useSignificantLocationChanges && self.beacons == options.beacons; + self.useVisits == options.useVisits && self.useSignificantLocationChanges == options.useSignificantLocationChanges && self.beacons == options.beacons && self.doIndoorsSurvey == options.doIndoorsSurvey; } @end diff --git a/RadarSDK/RadarVerificationManager.m b/RadarSDK/RadarVerificationManager.m index ec5dffc01..481d79682 100644 --- a/RadarSDK/RadarVerificationManager.m +++ b/RadarSDK/RadarVerificationManager.m @@ -98,6 +98,7 @@ - (void)trackVerifiedWithBeacons:(BOOL)beacons completionHandler:(RadarTrackVeri source:RadarLocationSourceForegroundLocation replayed:NO beacons:beacons + indoorsWhereAmIScan:@"" verified:YES attestationString:attestationString keyId:keyId From de0bae92982ef201935472f5304d33e269ac3f4a Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Fri, 26 Jul 2024 14:21:06 -0400 Subject: [PATCH 2/9] . --- Example/Example/AppDelegate.swift | 6 +++ RadarSDK/Include/RadarTrackingOptions.h | 2 +- RadarSDK/Radar.m | 68 +++++++++++++++++-------- RadarSDK/RadarIndoorSurvey.m | 11 +--- RadarSDK/RadarLocationManager.m | 4 +- RadarSDK/RadarSettings.m | 5 +- RadarSDK/RadarTrackingOptions.m | 14 ++--- 7 files changed, 67 insertions(+), 43 deletions(-) diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index 6ddbdce3c..a3eca7427 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -100,6 +100,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIWindowSceneDelegate, UN print("TrackVerified: status = \(status); token = \(token?.dictionaryValue())") } } + + demoButton(text: "trackOnce with beacons and indoors") { + Radar.trackOnce(desiredAccuracy: .high, beacons: true) { (status, location, events, user) in + print("Track once: status = \(Radar.stringForStatus(status)); location = \(String(describing: location)); events = \(String(describing: events)); user = \(String(describing: user))") + } + } demoButton(text: "searchPlaces") { // In the Radar dashboard settings diff --git a/RadarSDK/Include/RadarTrackingOptions.h b/RadarSDK/Include/RadarTrackingOptions.h index 27b20bb8f..84f742d5f 100644 --- a/RadarSDK/Include/RadarTrackingOptions.h +++ b/RadarSDK/Include/RadarTrackingOptions.h @@ -154,7 +154,7 @@ typedef NS_ENUM(NSInteger, RadarTrackingOptionsSyncLocations) { */ @property (nonatomic, assign) BOOL beacons; -@property (nonatomic, assign) BOOL doIndoorsSurvey; +@property (nonatomic, assign) BOOL indoors; /** Updates about every 30 seconds while moving or stopped. Moderate battery usage. Shows the flashing blue status bar during tracking. diff --git a/RadarSDK/Radar.m b/RadarSDK/Radar.m index febbb68fb..1d2dc5dfc 100644 --- a/RadarSDK/Radar.m +++ b/RadarSDK/Radar.m @@ -166,15 +166,7 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire return; } - // TODO indoors...?? - // TODO indoors...?? - // TODO indoors...?? - // TODO indoors...?? - // TODO add indoors call / callback logic here?? - // it's similar --- but different?? --- than LocationManager's sendLocation...? - // ALSO it doesn't use/call/care about useRadarModifiedBeacon...? - - void (^callTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { + void (^callTrackAPI)(NSArray *_Nullable, NSString *_Nullable) = ^(NSArray *_Nullable beacons, NSString *_Nullable indoorsWhereAmIScan) { [[RadarAPIClient sharedInstance] trackWithLocation:location stopped:stopped @@ -182,7 +174,7 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire source:RadarLocationSourceForegroundLocation replayed:NO beacons:beacons - indoorsWhereAmIScan:@"" + indoorsWhereAmIScan:indoorsWhereAmIScan completionHandler:^(RadarStatus status, NSDictionary *_Nullable res, NSArray *_Nullable events, RadarUser *_Nullable user, NSArray *_Nullable nearbyGeofences, RadarConfig *_Nullable config, RadarVerifiedLocationToken *_Nullable token) { if (status == RadarStatusSuccess) { @@ -201,6 +193,42 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire }]; }; + // callback used below, after (possibly) fetching beacons and ranging on them. + // at this point, we have beacons but have not yet done the indoor survey, which we might do or not (based on RTO options) + void (^maybeIndoorSurveyThenCallTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { + // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? + // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? + // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? + // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? + // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? + // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? + // -------------------------------- + // should this be exposed in a different call i.e. + // if there is Radar.trackOnce(desiredAccuracy: .high, beacons: true) + // should there be Radar.trackOnce(desiredAccuracy: .high, indoors: true) + // ...........??????? + // -------------------------------- + if(true) { + // do indoor survey, then call track api with the beacons and the indoor survey + [[RadarIndoorSurvey sharedInstance] start:@"WHEREAMI" + forLength:WHERE_AM_I_DURATION_SECONDS + withKnownLocation:location + isWhereAmIScan:YES + withCompletionHandler:^(NSString *_Nullable indoorsWhereAmIScan) { + + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug + message:[NSString stringWithFormat:@"received indoor start indoorsWhereAmIScan: %lu", (unsigned long)indoorsWhereAmIScan.length]]; + + callTrackAPI(beacons, indoorsWhereAmIScan); + }]; + + } else { + // no indoor survey -- just call track api with the given beacons + callTrackAPI(beacons, nil); + } + }; + + if (beacons) { [[RadarAPIClient sharedInstance] searchBeaconsNear:location @@ -215,12 +243,12 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire [[RadarBeaconManager sharedInstance] rangeBeaconUUIDs:beaconUUIDs completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { if (status != RadarStatusSuccess || !beacons) { - callTrackAPI(nil); + maybeIndoorSurveyThenCallTrackAPI(nil); return; } - callTrackAPI(beacons); + maybeIndoorSurveyThenCallTrackAPI(beacons); }]; }]; } else if (beacons && beacons.count) { @@ -230,31 +258,25 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire [[RadarBeaconManager sharedInstance] rangeBeacons:beacons completionHandler:^(RadarStatus status, NSArray *_Nullable beacons) { if (status != RadarStatusSuccess || !beacons) { - callTrackAPI(nil); + maybeIndoorSurveyThenCallTrackAPI(nil); return; } - callTrackAPI(beacons); + maybeIndoorSurveyThenCallTrackAPI(beacons); }]; }]; } else { - callTrackAPI(@[]); + maybeIndoorSurveyThenCallTrackAPI(@[]); } }]; } else { - callTrackAPI(nil); + maybeIndoorSurveyThenCallTrackAPI(nil); } }]; } + (void)trackOnceWithLocation:(CLLocation *)location completionHandler:(RadarTrackCompletionHandler)completionHandler { - // TODO do indoors stuff here too...??? - // TODO do indoors stuff here too...??? - // TODO do indoors stuff here too...??? - // TODO do indoors stuff here too...??? - // TODO do indoors stuff here too...??? - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo type:RadarLogTypeSDKCall message:@"trackOnce()"]; [[RadarAPIClient sharedInstance] trackWithLocation:location stopped:NO @@ -1035,6 +1057,8 @@ + (void)getMatrixFromOrigins:(NSArray *_Nonnull)origins #pragma mark - Indoors +// called by waypoint (and others?) to trigger a place survey for a given length +// i.e. record a bluetooth fingerprint and store it + (void)doIndoorSurvey:(NSString *)placeLabel forLength:(int)surveyLengthSeconds completionHandler:(RadarIndoorsSurveyCompletionHandler)completionHandler { diff --git a/RadarSDK/RadarIndoorSurvey.m b/RadarSDK/RadarIndoorSurvey.m index 6a7c6bfcf..315a15bb9 100644 --- a/RadarSDK/RadarIndoorSurvey.m +++ b/RadarSDK/RadarIndoorSurvey.m @@ -192,16 +192,7 @@ - (void)stopScanning { // ML server for training purposes // POST payload - // TODO move to prod server..? - // FIXME not working right now - // FIXME not working right now - // FIXME not working right now - // FIXME not working right now - // FIXME not working right now - // FIXME not working right now - // FIXME not working right now - // FIXME not working right now - NSURL *url = [NSURL URLWithString:@"https://ml-prod.radarindoors.com/scan_results"]; + NSURL *url = [NSURL URLWithString:@"https://ml-staging.radarindoors.com/scan_results"]; NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url]; [urlRequest setHTTPMethod:@"POST"]; diff --git a/RadarSDK/RadarLocationManager.m b/RadarSDK/RadarLocationManager.m index c46d84a57..956c4f0a9 100644 --- a/RadarSDK/RadarLocationManager.m +++ b/RadarSDK/RadarLocationManager.m @@ -391,7 +391,7 @@ - (void)updateTracking:(CLLocation *)location fromInitialize:(BOOL)fromInitializ [self removeSyncedBeacons]; } - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"options.doIndoorsSurvey = %d", options.doIndoorsSurvey]]; + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"options.indoors = %d", options.indoors]]; } else { [self stopUpdates]; [self removeAllRegions]; @@ -925,7 +925,7 @@ - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarL // FIXME // FIXME // FIXME - if(true || options.doIndoorsSurvey) { + if(true || options.indoors) { // do indoor survey, then call track api with the beacons and the indoor survey [[RadarIndoorSurvey sharedInstance] start:@"WHEREAMI" forLength:WHERE_AM_I_DURATION_SECONDS diff --git a/RadarSDK/RadarSettings.m b/RadarSDK/RadarSettings.m index 9bbbe1d31..950772bb4 100644 --- a/RadarSDK/RadarSettings.m +++ b/RadarSDK/RadarSettings.m @@ -39,9 +39,12 @@ @implementation RadarSettings static NSString *const kLogLevel = @"radar-logLevel"; static NSString *const kBeaconUUIDs = @"radar-beaconUUIDs"; static NSString *const kHost = @"radar-host"; + // static NSString *const kDefaultHost = @"https://api.radar.io"; // static NSString *const kDefaultHost = @"https://api.radar-staging.com"; -static NSString *const kDefaultHost = @"https://radar-server-dev-greg.ngrok.io"; +// static NSString *const kDefaultHost = @"https://radar-server-dev-greg.ngrok.io"; +static NSString *const kDefaultHost = @"https://api-greg.radar-staging.com"; + static NSString *const kLastTrackedTime = @"radar-lastTrackedTime"; static NSString *const kVerifiedHost = @"radar-verifiedHost"; static NSString *const kDefaultVerifiedHost = @"https://api-verified.radar.io"; diff --git a/RadarSDK/RadarTrackingOptions.m b/RadarSDK/RadarTrackingOptions.m index 5688824eb..1b1e6eea5 100644 --- a/RadarSDK/RadarTrackingOptions.m +++ b/RadarSDK/RadarTrackingOptions.m @@ -29,7 +29,7 @@ @implementation RadarTrackingOptions NSString *const kUseVisits = @"useVisits"; NSString *const kUseSignificantLocationChanges = @"useSignificantLocationChanges"; NSString *const kBeacons = @"beacons"; -NSString *const kDoIndoorsSurvey = @"doIndoorsSurvey"; +NSString *const kIndoors = @"indoors"; NSString *const kDesiredAccuracyHigh = @"high"; NSString *const kDesiredAccuracyMedium = @"medium"; @@ -64,7 +64,7 @@ + (RadarTrackingOptions *)presetContinuous { options.useVisits = NO; options.useSignificantLocationChanges = NO; options.beacons = NO; - options.doIndoorsSurvey = NO; + options.indoors = NO; return options; } @@ -89,7 +89,7 @@ + (RadarTrackingOptions *)presetResponsive { options.useVisits = YES; options.useSignificantLocationChanges = YES; options.beacons = NO; - options.doIndoorsSurvey = NO; + options.indoors = NO; return options; } @@ -114,7 +114,7 @@ + (RadarTrackingOptions *)presetEfficient { options.useVisits = YES; options.useSignificantLocationChanges = NO; options.beacons = NO; - options.doIndoorsSurvey = NO; + options.indoors = NO; return options; } @@ -243,7 +243,7 @@ + (RadarTrackingOptions *)trackingOptionsFromDictionary:(NSDictionary *)dict { options.useVisits = [dict[kUseVisits] boolValue]; options.useSignificantLocationChanges = [dict[kUseSignificantLocationChanges] boolValue]; options.beacons = [dict[kBeacons] boolValue]; - options.doIndoorsSurvey = [dict[kDoIndoorsSurvey] boolValue]; + options.indoors = [dict[kIndoors] boolValue]; return options; } @@ -276,7 +276,7 @@ - (NSDictionary *)dictionaryValue { dict[kUseVisits] = @(self.useVisits); dict[kUseSignificantLocationChanges] = @(self.useSignificantLocationChanges); dict[kBeacons] = @(self.beacons); - dict[kDoIndoorsSurvey] = @(self.doIndoorsSurvey); + dict[kIndoors] = @(self.indoors); return dict; } @@ -305,7 +305,7 @@ - (BOOL)isEqual:(id)object { self.syncLocations == options.syncLocations && self.replay == options.replay && self.showBlueBar == options.showBlueBar && self.useStoppedGeofence == options.useStoppedGeofence && self.stoppedGeofenceRadius == options.stoppedGeofenceRadius && self.useMovingGeofence == options.useMovingGeofence && self.movingGeofenceRadius == options.movingGeofenceRadius && self.syncGeofences == options.syncGeofences && - self.useVisits == options.useVisits && self.useSignificantLocationChanges == options.useSignificantLocationChanges && self.beacons == options.beacons && self.doIndoorsSurvey == options.doIndoorsSurvey; + self.useVisits == options.useVisits && self.useSignificantLocationChanges == options.useSignificantLocationChanges && self.beacons == options.beacons && self.indoors == options.indoors; } @end From 769580a783b37e709e369670a0236d9a1907ead5 Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Tue, 30 Jul 2024 10:02:33 -0400 Subject: [PATCH 3/9] . --- RadarSDK/Radar.m | 17 ++++------------- RadarSDK/RadarAPIClient.m | 5 +++++ RadarSDK/RadarEvent.m | 18 ++++++++---------- RadarSDK/RadarLocationManager.m | 14 ++++---------- 4 files changed, 21 insertions(+), 33 deletions(-) diff --git a/RadarSDK/Radar.m b/RadarSDK/Radar.m index 1d2dc5dfc..7b7c7ba9e 100644 --- a/RadarSDK/Radar.m +++ b/RadarSDK/Radar.m @@ -196,19 +196,10 @@ + (void)trackOnceWithDesiredAccuracy:(RadarTrackingOptionsDesiredAccuracy)desire // callback used below, after (possibly) fetching beacons and ranging on them. // at this point, we have beacons but have not yet done the indoor survey, which we might do or not (based on RTO options) void (^maybeIndoorSurveyThenCallTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { - // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? - // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? - // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? - // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? - // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? - // FIXME track once doesn't use RTO/options...?? how to get options.indoors..?? - // -------------------------------- - // should this be exposed in a different call i.e. - // if there is Radar.trackOnce(desiredAccuracy: .high, beacons: true) - // should there be Radar.trackOnce(desiredAccuracy: .high, indoors: true) - // ...........??????? - // -------------------------------- - if(true) { + // exceptionally, we look into the current options/RTOs to figure out + // if indoors is enabled + RadarTrackingOptions *options = [Radar getTrackingOptions]; + if(options.indoors) { // do indoor survey, then call track api with the beacons and the indoor survey [[RadarIndoorSurvey sharedInstance] start:@"WHEREAMI" forLength:WHERE_AM_I_DURATION_SECONDS diff --git a/RadarSDK/RadarAPIClient.m b/RadarSDK/RadarAPIClient.m index bf3b1cf71..61496b85c 100644 --- a/RadarSDK/RadarAPIClient.m +++ b/RadarSDK/RadarAPIClient.m @@ -357,6 +357,11 @@ - (void)trackWithLocation:(CLLocation *_Nonnull)location [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Checking replays in API client | replayCount = %lu", (unsigned long)replayCount]]; NSMutableDictionary *requestParams = [params mutableCopy]; + // log all params + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Request params: %@", requestParams]]; + // just OS print them + NSLog(@"Request params: %@", requestParams); + BOOL replaying = options.replay == RadarTrackingOptionsReplayAll && replayCount > 0 && !verified; if (replaying) { [[RadarReplayBuffer sharedInstance] flushReplaysWithCompletionHandler:params completionHandler:^(RadarStatus status, NSDictionary *_Nullable res) { diff --git a/RadarSDK/RadarEvent.m b/RadarSDK/RadarEvent.m index 1fecddf78..ae9d9e21d 100644 --- a/RadarSDK/RadarEvent.m +++ b/RadarSDK/RadarEvent.m @@ -298,16 +298,14 @@ - (instancetype _Nullable)initWithObject:(id)object { float locationCoordinatesLatitudeFloat = [locationCoordinatesLatitudeNumber floatValue]; id locationAccuracyObj = dict[@"locationAccuracy"]; - // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? - // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? - // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? - // FIXME why is this done..........? server side not responding well to accuracy being ... less/more... than...? why? - // if (locationAccuracyObj && [locationAccuracyObj isKindOfClass:[NSNumber class]]) { - if (YES) { - // FIXMED - // FIXMED - // NSNumber *locationAccuracyNumber = (NSNumber *)locationAccuracyObj; - NSNumber *locationAccuracyNumber = [NSNumber numberWithFloat:123.0]; + if (locationAccuracyObj && [locationAccuracyObj isKindOfClass:[NSNumber class]]) { + NSNumber *locationAccuracyNumber = (NSNumber *)locationAccuracyObj; + + // in indoors mode, override accuracy + RadarTrackingOptions *options = [Radar getTrackingOptions]; + if(options.indoors){ + locationAccuracyNumber = [NSNumber numberWithFloat:10.0]; + } location = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(locationCoordinatesLatitudeFloat, locationCoordinatesLongitudeFloat) altitude:-1 diff --git a/RadarSDK/RadarLocationManager.m b/RadarSDK/RadarLocationManager.m index 956c4f0a9..08ebff076 100644 --- a/RadarSDK/RadarLocationManager.m +++ b/RadarSDK/RadarLocationManager.m @@ -735,12 +735,9 @@ - (void)handleLocation:(CLLocation *)location source:(RadarLocationSource)source BOOL force = (source == RadarLocationSourceForegroundLocation || source == RadarLocationSourceManualLocation || source == RadarLocationSourceBeaconEnter || source == RadarLocationSourceBeaconExit || source == RadarLocationSourceVisitArrival); - // FIXME indoors --- don't do this.......>??? - // FIXME indoors --- don't do this.......>??? - // FIXME indoors --- don't do this.......>??? - // FIXME indoors --- don't do this.......>??? - // FIXME -- make sure to not skip location because of inaccurate...?? - force = true; + if(options.indoors) { + force = true; + } if (wasStopped && !force && location.horizontalAccuracy >= 1000 && options.desiredAccuracy != RadarTrackingOptionsDesiredAccuracyLow) { [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug @@ -922,10 +919,7 @@ - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarL // callback used below, after (possibly) fetching beacons and ranging on them. // at this point, we have beacons but have not yet done the indoor survey, which we might do or not (based on RTO options) void (^maybeIndoorSurveyThenCallTrackAPI)(NSArray *_Nullable) = ^(NSArray *_Nullable beacons) { - // FIXME - // FIXME - // FIXME - if(true || options.indoors) { + if(options.indoors) { // do indoor survey, then call track api with the beacons and the indoor survey [[RadarIndoorSurvey sharedInstance] start:@"WHEREAMI" forLength:WHERE_AM_I_DURATION_SECONDS From 3e9ffc7879db4932a9a4e9d8d430ab28f217ed3a Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Tue, 30 Jul 2024 10:03:32 -0400 Subject: [PATCH 4/9] . --- RadarSDK/RadarBeaconManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RadarSDK/RadarBeaconManager.m b/RadarSDK/RadarBeaconManager.m index 10695e4a3..619836bd0 100644 --- a/RadarSDK/RadarBeaconManager.m +++ b/RadarSDK/RadarBeaconManager.m @@ -303,7 +303,7 @@ - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(nonnull NS // log "same beacon" [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"same beacon!"]; if (beacon.rssi != 0 && beacon.rssi != radarBeacon.rssi) { - // OVERWRITING STALE RSSI!!!! + // overwriting stale rssi [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Overwriting stale RSSI: %ld", (long)radarBeacon.rssi]]; [radarBeacon setRssi:beacon.rssi]; } From 771f6a777bf2bfc5beef6c61115cd1252ddf5658 Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Tue, 30 Jul 2024 10:03:57 -0400 Subject: [PATCH 5/9] . --- Example/Example/AppDelegate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index a3eca7427..96618c68e 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -26,7 +26,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIWindowSceneDelegate, UN self.requestLocationPermissions() // Replace with a valid test publishable key - Radar.initialize(publishableKey: "prj_test_pk_2236cce4dabfd26f891738e119b66270be6d3d01") + Radar.initialize(publishableKey: "prj_test_pk_0000000000000000000000000000000000000000") Radar.setUserId("testUserId") Radar.setMetadata([ "foo": "bar" ]) Radar.setDelegate(self) From 530f82f0aaeb0074df09ff87a608292b6689881c Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Tue, 30 Jul 2024 10:05:29 -0400 Subject: [PATCH 6/9] . --- RadarSDK/RadarLogger.m | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/RadarSDK/RadarLogger.m b/RadarSDK/RadarLogger.m index 65d4e21de..0751c6b3e 100644 --- a/RadarSDK/RadarLogger.m +++ b/RadarSDK/RadarLogger.m @@ -49,19 +49,12 @@ - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSStr } - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSString *)message includeDate:(BOOL)includeDate includeBattery:(BOOL)includeBattery append:(BOOL)append{ - // RadarLogLevel logLevel = [RadarSettings logLevel]; - // if (level > logLevel) { - // return; - // } - - // NSString *dateString = [self.dateFormatter stringFromDate:[NSDate date]]; - includeDate = YES; - - // make date string that includes date, second and millisecond - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; - NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; + RadarLogLevel logLevel = [RadarSettings logLevel]; + if (level > logLevel) { + return; + } + NSString *dateString = [self.dateFormatter stringFromDate:[NSDate date]]; float batteryLevel = [self.device batteryLevel]; if (includeDate && includeBattery) { message = [NSString stringWithFormat:@"%@ | at %@ | with %2.f%% battery", message, dateString, batteryLevel*100]; @@ -70,19 +63,6 @@ - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSStr } else if (includeBattery) { message = [NSString stringWithFormat:@"%@ | with %2.f%% battery", message, batteryLevel*100]; } - - // ping own (indoors-related) log server for immediate prod remote logging - NSURL *url = [NSURL URLWithString:@"https://logs.radarindoors.com"]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - request.HTTPMethod = @"POST"; - [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - - NSDictionary *body = @{@"log": message, @"timestamp": dateString}; - NSData *data = [NSJSONSerialization dataWithJSONObject:body options:0 error:nil]; - request.HTTPBody = data; - NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request]; - [task resume]; - if (append) { [[RadarLogBuffer sharedInstance] write:level type:type message:message forcePersist:YES]; } else { @@ -98,4 +78,4 @@ - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSStr } } -@end +@end \ No newline at end of file From d8983ef74aaeb18bf7abfddf136f40bacbb26097 Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Tue, 30 Jul 2024 10:07:38 -0400 Subject: [PATCH 7/9] . --- RadarSDK/RadarAPIClient.m | 5 ----- RadarSDK/RadarLogger.m | 2 +- RadarSDK/RadarSdkConfiguration.m | 7 ------- RadarSDK/RadarSettings.m | 7 +------ RadarSDK/RadarTrackingOptions.m | 2 +- 5 files changed, 3 insertions(+), 20 deletions(-) diff --git a/RadarSDK/RadarAPIClient.m b/RadarSDK/RadarAPIClient.m index 61496b85c..bf3b1cf71 100644 --- a/RadarSDK/RadarAPIClient.m +++ b/RadarSDK/RadarAPIClient.m @@ -357,11 +357,6 @@ - (void)trackWithLocation:(CLLocation *_Nonnull)location [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Checking replays in API client | replayCount = %lu", (unsigned long)replayCount]]; NSMutableDictionary *requestParams = [params mutableCopy]; - // log all params - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"Request params: %@", requestParams]]; - // just OS print them - NSLog(@"Request params: %@", requestParams); - BOOL replaying = options.replay == RadarTrackingOptionsReplayAll && replayCount > 0 && !verified; if (replaying) { [[RadarReplayBuffer sharedInstance] flushReplaysWithCompletionHandler:params completionHandler:^(RadarStatus status, NSDictionary *_Nullable res) { diff --git a/RadarSDK/RadarLogger.m b/RadarSDK/RadarLogger.m index 0751c6b3e..b5cab0913 100644 --- a/RadarSDK/RadarLogger.m +++ b/RadarSDK/RadarLogger.m @@ -78,4 +78,4 @@ - (void)logWithLevel:(RadarLogLevel)level type:(RadarLogType)type message:(NSStr } } -@end \ No newline at end of file +@end diff --git a/RadarSDK/RadarSdkConfiguration.m b/RadarSDK/RadarSdkConfiguration.m index c04031d97..1130bbb2a 100644 --- a/RadarSDK/RadarSdkConfiguration.m +++ b/RadarSDK/RadarSdkConfiguration.m @@ -17,9 +17,6 @@ @implementation RadarSdkConfiguration - (instancetype)initWithDict:(NSDictionary *)dict { - // log the dict - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"RadarSdkConfiguration initWithDict: %@", dict]]; - self = [super init]; if (self == nil) { return nil; @@ -62,13 +59,9 @@ - (instancetype)initWithDict:(NSDictionary *)dict { } NSObject *useRadarModifiedBeaconObj = dict[@"useRadarModifiedBeacon"]; - // log useRadarModifiedBeaconObj - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"useRadarModifiedBeaconObj: %@", useRadarModifiedBeaconObj]]; _useRadarModifiedBeacon = NO; if (useRadarModifiedBeaconObj && [useRadarModifiedBeaconObj isKindOfClass:[NSNumber class]]) { - // log "setting _useRadarModifiedBeacon!!" - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:@"setting _useRadarModifiedBeacon!!"]; _useRadarModifiedBeacon = [(NSNumber *)useRadarModifiedBeaconObj boolValue]; } diff --git a/RadarSDK/RadarSettings.m b/RadarSDK/RadarSettings.m index 950772bb4..190b3bb89 100644 --- a/RadarSDK/RadarSettings.m +++ b/RadarSDK/RadarSettings.m @@ -39,12 +39,7 @@ @implementation RadarSettings static NSString *const kLogLevel = @"radar-logLevel"; static NSString *const kBeaconUUIDs = @"radar-beaconUUIDs"; static NSString *const kHost = @"radar-host"; - -// static NSString *const kDefaultHost = @"https://api.radar.io"; -// static NSString *const kDefaultHost = @"https://api.radar-staging.com"; -// static NSString *const kDefaultHost = @"https://radar-server-dev-greg.ngrok.io"; -static NSString *const kDefaultHost = @"https://api-greg.radar-staging.com"; - +static NSString *const kDefaultHost = @"https://api.radar.io"; static NSString *const kLastTrackedTime = @"radar-lastTrackedTime"; static NSString *const kVerifiedHost = @"radar-verifiedHost"; static NSString *const kDefaultVerifiedHost = @"https://api-verified.radar.io"; diff --git a/RadarSDK/RadarTrackingOptions.m b/RadarSDK/RadarTrackingOptions.m index 1b1e6eea5..640e09f4c 100644 --- a/RadarSDK/RadarTrackingOptions.m +++ b/RadarSDK/RadarTrackingOptions.m @@ -47,7 +47,7 @@ + (RadarTrackingOptions *)presetContinuous { RadarTrackingOptions *options = [RadarTrackingOptions new]; options.desiredStoppedUpdateInterval = 30; options.desiredMovingUpdateInterval = 30; - options.desiredSyncInterval = 10; + options.desiredSyncInterval = 20; options.desiredAccuracy = RadarTrackingOptionsDesiredAccuracyHigh; options.stopDuration = 140; options.stopDistance = 70; From f3154953b8f620b2eff43faf3e28f01f6ae4ff14 Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Tue, 30 Jul 2024 10:09:46 -0400 Subject: [PATCH 8/9] . --- RadarSDK/RadarLocationManager.m | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/RadarSDK/RadarLocationManager.m b/RadarSDK/RadarLocationManager.m index 08ebff076..0822d8694 100644 --- a/RadarSDK/RadarLocationManager.m +++ b/RadarSDK/RadarLocationManager.m @@ -390,8 +390,6 @@ - (void)updateTracking:(CLLocation *)location fromInitialize:(BOOL)fromInitializ if (!options.beacons) { [self removeSyncedBeacons]; } - - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug message:[NSString stringWithFormat:@"options.indoors = %d", options.indoors]]; } else { [self stopUpdates]; [self removeAllRegions]; @@ -704,9 +702,6 @@ - (void)handleLocation:(CLLocation *)location source:(RadarLocationSource)source return; } - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug - message:[NSString stringWithFormat:@"RadarIndoorSurvey sharedInstance isScanning: %d", [[RadarIndoorSurvey sharedInstance] isScanning]]]; - if([[RadarIndoorSurvey sharedInstance] isScanning]) { if(![[RadarIndoorSurvey sharedInstance] isWhereAmIScan]) { // we _are_ currently scanning, but we are not in the "where am i" mode i.e. @@ -887,17 +882,13 @@ - (void)handleLocation:(CLLocation *)location source:(RadarLocationSource)source - (void)sendLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarLocationSource)source replayed:(BOOL)replayed beacons:(NSArray *_Nullable)beacons { [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug - message:[NSString stringWithFormat:@"sendLocation | source = %@; location = %@; stopped = %d; replayed = %d; beacons = %@", + message:[NSString stringWithFormat:@"Sending location | source = %@; location = %@; stopped = %d; replayed = %d; beacons = %@", [Radar stringForLocationSource:source], location, stopped, replayed, beacons]]; self.sending = YES; RadarTrackingOptions *options = [Radar getTrackingOptions]; - // log RadarSettings useRadarModifiedBeacon - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelDebug - message:[NSString stringWithFormat:@"useRadarModifiedBeacon = %d", [RadarSettings useRadarModifiedBeacon]]]; - if ([RadarSettings useRadarModifiedBeacon]) { void (^callTrackAPI)(NSArray *_Nullable, NSString *_Nullable) = ^(NSArray *_Nullable beacons, NSString *_Nullable indoorsWhereAmIScan) { [[RadarAPIClient sharedInstance] trackWithLocation:location From bcba999b46e976efb5e459d6b966aec6f355be69 Mon Sep 17 00:00:00 2001 From: Greg Sadetsky Date: Tue, 30 Jul 2024 14:15:52 -0400 Subject: [PATCH 9/9] . --- Example/Example/AppDelegate.swift | 8 +++++- RadarSDK/RadarAPIClient.m | 1 - RadarSDK/RadarEvent.m | 2 ++ RadarSDK/RadarIndoorSurvey.m | 45 +------------------------------ RadarSDK/RadarSdkConfiguration.m | 2 -- 5 files changed, 10 insertions(+), 48 deletions(-) diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index 96618c68e..ce307107f 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -101,11 +101,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIWindowSceneDelegate, UN } } - demoButton(text: "trackOnce with beacons and indoors") { + demoButton(text: "indoors: trackOnce") { Radar.trackOnce(desiredAccuracy: .high, beacons: true) { (status, location, events, user) in print("Track once: status = \(Radar.stringForStatus(status)); location = \(String(describing: location)); events = \(String(describing: events)); user = \(String(describing: user))") } } + + demoButton(text: "indoors: doIndoorSurvey") { + Radar.doIndoorSurvey("example-app-fake-survey", forLength: 10) { (result) in + print("doIndoorSurvey done") + } + } demoButton(text: "searchPlaces") { // In the Radar dashboard settings diff --git a/RadarSDK/RadarAPIClient.m b/RadarSDK/RadarAPIClient.m index bf3b1cf71..b9a48e983 100644 --- a/RadarSDK/RadarAPIClient.m +++ b/RadarSDK/RadarAPIClient.m @@ -303,7 +303,6 @@ - (void)trackWithLocation:(CLLocation *_Nonnull)location params[@"beacons"] = [RadarBeacon arrayForBeacons:beacons]; } - NSLog(@"indoorsWhereAmIScan length: %lu", (unsigned long)indoorsWhereAmIScan.length); if (indoorsWhereAmIScan) { params[@"indoorsWhereAmIScan"] = indoorsWhereAmIScan; } diff --git a/RadarSDK/RadarEvent.m b/RadarSDK/RadarEvent.m index ae9d9e21d..c4f12e4f8 100644 --- a/RadarSDK/RadarEvent.m +++ b/RadarSDK/RadarEvent.m @@ -5,6 +5,7 @@ // Copyright © 2019 Radar Labs, Inc. All rights reserved. // +#import "Radar.h" #import "RadarEvent.h" #import "RadarBeacon+Internal.h" #import "RadarEvent+Internal.h" @@ -12,6 +13,7 @@ #import "RadarGeofence+Internal.h" #import "RadarPlace+Internal.h" #import "RadarRegion+Internal.h" +#import "RadarTrackingOptions.h" #import "RadarTrip+Internal.h" #import "RadarUtils.h" diff --git a/RadarSDK/RadarIndoorSurvey.m b/RadarSDK/RadarIndoorSurvey.m index 315a15bb9..2630e01f4 100644 --- a/RadarSDK/RadarIndoorSurvey.m +++ b/RadarSDK/RadarIndoorSurvey.m @@ -36,16 +36,10 @@ - (BOOL)isWhereAmIScan { - (void)start:(NSString *)placeLabel forLength:(int)surveyLengthSeconds withKnownLocation:(CLLocation *)knownLocation isWhereAmIScan:(BOOL)isWhereAmIScan withCompletionHandler:(RadarIndoorsSurveyCompletionHandler)completionHandler { - // convert to [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:message]; call - // NSLog(@"start called with placeLabel: %@, surveyLengthSeconds: %d, isWhereAmIScan: %d", placeLabel, surveyLengthSeconds, isWhereAmIScan); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"RadarIndoorSurvey start called with placeLabel: %@, surveyLengthSeconds: %d, isWhereAmIScan: %d", placeLabel, surveyLengthSeconds, isWhereAmIScan]]; - - // log self.isScanning - // NSLog(@"self.isScanning: %d", self.isScanning); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"self.isScanning: %d", self.isScanning]]; if(self.isScanning) { - // NSLog(@"Error: start called while already scanning"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelError message:@"Error: start called while already scanning"]; // call callback, pass bad data @@ -68,8 +62,6 @@ - (void)start:(NSString *)placeLabel forLength:(int)surveyLengthSeconds withKnow // if isWhereAmIScan but no knownLocation, throw error // as we are expecting to have been called from track if (isWhereAmIScan && !knownLocation) { - // convert to [[RadarLogger sharedInstance] - // NSLog(@"Error: start called with isWhereAmIScan but no knownLocation"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelError message:@"Error: start called with isWhereAmIScan but no knownLocation"]; completionHandler(@"Error: start called with isWhereAmIScan but no knownLocation"); self.isScanning = NO; @@ -91,13 +83,9 @@ - (void)start:(NSString *)placeLabel forLength:(int)surveyLengthSeconds withKnow return; } - // NSLog(@"location: %f, %f", location.coordinate.latitude, location.coordinate.longitude); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"location: %f, %f", location.coordinate.latitude, location.coordinate.longitude]]; - // print location object as is - // NSLog(@"%@", location); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"%@", location]]; - // set self.locationAtTimeOfSurveyStart to location self.locationAtTimeOfSurveyStart = location; [self kickOffMotionAndBluetooth:surveyLengthSeconds]; @@ -106,23 +94,17 @@ - (void)start:(NSString *)placeLabel forLength:(int)surveyLengthSeconds withKnow } - (void)kickOffMotionAndBluetooth:(int)surveyLengthSeconds { - // NSLog(@"kicking off CMMotionManager"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"kicking off CMMotionManager"]; self.motionManager = [[CMMotionManager alloc] init]; - // motionManager.startMagnetometerUpdates(to: OperationQueue.main, withHandler: updateMotionManagerHandler!) [self.motionManager startMagnetometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMagnetometerData *magnetometerData, NSError *error) { if (error) { - // NSLog(@"startMagnetometerUpdatesToQueue error: %@", error); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelError message:[NSString stringWithFormat:@"startMagnetometerUpdatesToQueue error: %@", error]]; } else { self.lastMagnetometerData = magnetometerData; } }]; - // NSLog(@"kicking off CBCentralManager"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"kicking off CBCentralManager"]; - // print time - // NSLog(@"time: %f", [[NSDate date] timeIntervalSince1970]); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"time: %f", [[NSDate date] timeIntervalSince1970]]]; // kick off the survey by init'ing the corebluetooth manager @@ -131,15 +113,12 @@ - (void)kickOffMotionAndBluetooth:(int)surveyLengthSeconds { } - (void)startScanning { - // NSLog(@"startScanning called --- calling scanForPeripheralsWithServices"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"startScanning called --- calling scanForPeripheralsWithServices"]; [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @YES}]; } - (void)stopScanning { - // NSLog(@"stopScanning called"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"stopScanning called"]; - // NSLog(@"time: %f", [[NSDate date] timeIntervalSince1970]); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"time: %f", [[NSDate date] timeIntervalSince1970]]]; [self.centralManager stopScan]; @@ -150,36 +129,27 @@ - (void)stopScanning { // join all self.bluetoothReadings with newlines and POST to server NSString *payload = [self.bluetoothReadings componentsJoinedByString:@"\n"]; - // if [RadarUtils isSimulator] , put fake data into payload - - // NSLog(@"[RadarUtils isSimulator]: %d", [RadarUtils isSimulator]); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"[RadarUtils isSimulator]: %d", [RadarUtils isSimulator]]]; if ([RadarUtils isSimulator]) { payload = @"?time=1716583686.556668&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=C9AC95A0-D6B5-D57F-014B-0FDD11D51E7E&peripheral.name=(no%20name)&rssi=-88&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.559950&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=540803B9-86A3-CF2E-2A4B-1B23C6DB0214&peripheral.name=%5BTV%5D%20Samsung%209%20Series%20(86)&rssi=-71&manufacturerId=7500&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.560602&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=540803B9-86A3-CF2E-2A4B-1B23C6DB0214&peripheral.name=%5BTV%5D%20Samsung%209%20Series%20(86)&rssi=-71&manufacturerId=7500&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.563503&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=E25D13C2-08A0-9598-327A-CC4B2F782E53&peripheral.name=(no%20name)&rssi=-70&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.568083&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=0B9BD1B0-D482-31D2-B723-882E5AD9FCEA&peripheral.name=(no%20name)&rssi=-88&manufacturerId=0600&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.572948&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=D48D165B-FE69-C705-6B14-4000822C5EC7&peripheral.name=(no%20name)&rssi=-78&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.573204&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=D48D165B-FE69-C705-6B14-4000822C5EC7&peripheral.name=(no%20name)&rssi=-78&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.573577&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=E6FD4D8E-6C80-EACC-6B93-9DDB8D9AAAA5&peripheral.name=(no%20name)&rssi=-73&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-35.025116&magnetometer.field.y=-112.979324&magnetometer.field.z=-240.243347&magnetometer.timestamp=65614.479717&magnetometer.field.magnitude=267.783406\n?time=1716583686.590971&label=FAKE-SIMULATOR-FAKE-SIMULATOR-geofence.description:RDR-T__geofence._id:664dfae54dfd1b59d5aff925&peripheral.identifier=571CE11A-F8BE-43AC-460C-C1A9FA3F0406&peripheral.name=(no%20name)&rssi=-64&manufacturerId=&scanId=4FCAE527-99B8-4BB8-81F3-75D41C2323B1&serviceUUIDs=(no%20services)&location.coordinate.latitude=40.734173&location.coordinate.longitude=-73.990878&location.horizontalAccuracy=21.840953&location.verticalAccuracy=24.163757&location.altitude=41.885521&location.ellipsoidalAltitude=8.913273&location.timestamp=-0.000000&location.floor=0&sdkVersion=3.9.12&deviceType=iOS&deviceMake=Apple&deviceModel=iPhone14,2&deviceOS=17.4.1&magnetometer.field.x=-29.425323&magnetometer.field.y=-112.600601&magnetometer.field.z=-246.101929&magnetometer.timestamp=65614.520519&magnetometer.field.magnitude=272.233180\n"; } - // print length of payload - // NSLog(@"payload length: %lu", (unsigned long)[payload length]); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"payload length: %lu", (unsigned long)[payload length]]]; // compress payload and base64 encode it - // compress payload NSData *compressedData = [payload dataUsingEncoding:NSUTF8StringEncoding]; NSData *compressedDataGzipped = [compressedData gzippedData]; // print length of compressed payload - // NSLog(@"compressedDataGzipped length: %lu", (unsigned long)[compressedDataGzipped length]); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"compressedDataGzipped length: %lu", (unsigned long)[compressedDataGzipped length]]]; // base64 encode NSString *compressedDataGzippedBase64 = [compressedDataGzipped base64EncodedStringWithOptions:0]; // print length of base64 encoded payload - // NSLog(@"compressedDataGzippedBase64 length: %lu", (unsigned long)[compressedDataGzippedBase64 length]); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"compressedDataGzippedBase64 length: %lu", (unsigned long)[compressedDataGzippedBase64 length]]]; - // NSLog(@"self.isWhereAmIScan %d", self.isWhereAmIScan); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"self.isWhereAmIScan %d", self.isWhereAmIScan]]; // if self.isWhereAmIScan, call callback with the payload string @@ -202,7 +172,6 @@ - (void)stopScanning { if (data && self.completionHandler) { // decode data to string NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - // NSLog(@"responseString: %@", responseString); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:[NSString stringWithFormat:@"responseString: %@", responseString]]; self.completionHandler(responseString); } @@ -210,22 +179,16 @@ - (void)stopScanning { [task resume]; } - // NSLog(@"callign removeAllObjects, clearing scanId, etc."); - [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"callign removeAllObjects, clearing scanId, etc."]; + [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"calling removeAllObjects, clearing scanId, etc."]; // removeAllObjects from bluetooth readings i.e. clear array [self.bluetoothReadings removeAllObjects]; - // reset self.scanId self.scanId = nil; - // reset self.locationAtTimeOfSurveyStart self.locationAtTimeOfSurveyStart = nil; - // reset self.lastMagnetometerData self.lastMagnetometerData = nil; - // NSLog(@"stopScanning end"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"stopScanning end"]; - // set self.isScanning to NO self.isScanning = NO; } @@ -274,10 +237,7 @@ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeri // join service uuids into string or store "(no services)" if array is empty/nil NSString *serviceUUIDsString = serviceUUIDs ? [serviceUUIDs componentsJoinedByString:@","] : @"(no services)"; - // extract kCBAdvDataIsConnectable from advertisement data if it's available NSNumber *isConnectable = advertisementData[@"kCBAdvDataIsConnectable"]; - - // extract kCBAdvDataTxPowerLevel from advertisement data if it's available NSNumber *txPowerLevel = advertisementData[@"kCBAdvDataTxPowerLevel"]; NSURLComponents *components = [NSURLComponents componentsWithString: @""]; @@ -315,9 +275,7 @@ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeri [NSURLQueryItem queryItemWithName:@"magnetometer.timestamp" value:[NSString stringWithFormat:@"%f", self.lastMagnetometerData.timestamp]], [NSURLQueryItem queryItemWithName:@"magnetometer.field.magnitude" value:[NSString stringWithFormat:@"%f", sqrt(pow(self.lastMagnetometerData.magneticField.x, 2) + pow(self.lastMagnetometerData.magneticField.y, 2) + pow(self.lastMagnetometerData.magneticField.z, 2))]], - // inject isConnectable [NSURLQueryItem queryItemWithName:@"isConnectable" value:[isConnectable stringValue]], - // inject txPowerLevel [NSURLQueryItem queryItemWithName:@"txPowerLevel" value:[txPowerLevel stringValue]] ]]; @@ -334,7 +292,6 @@ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeri } - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { - // NSLog(@"centralManager didConnectPeripheral, calling stopScanning"); [[RadarLogger sharedInstance] logWithLevel:RadarLogLevelInfo message:@"centralManager didConnectPeripheral, calling stopScanning"]; [self stopScanning]; } diff --git a/RadarSDK/RadarSdkConfiguration.m b/RadarSDK/RadarSdkConfiguration.m index 1130bbb2a..b7cf3c0b8 100644 --- a/RadarSDK/RadarSdkConfiguration.m +++ b/RadarSDK/RadarSdkConfiguration.m @@ -9,7 +9,6 @@ #include "Radar.h" #import "RadarLog.h" -#import "RadarLogger.h" #import "RadarUtils.h" #import "RadarAPIClient.h" #import "RadarSettings.h" @@ -59,7 +58,6 @@ - (instancetype)initWithDict:(NSDictionary *)dict { } NSObject *useRadarModifiedBeaconObj = dict[@"useRadarModifiedBeacon"]; - _useRadarModifiedBeacon = NO; if (useRadarModifiedBeaconObj && [useRadarModifiedBeaconObj isKindOfClass:[NSNumber class]]) { _useRadarModifiedBeacon = [(NSNumber *)useRadarModifiedBeaconObj boolValue];