forked from organicmaps/organicmaps
[ios] Refactored location manager.
This commit is contained in:
parent
bdf88faf8b
commit
720165a8c3
37 changed files with 1076 additions and 1159 deletions
|
@ -1,7 +1,6 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MWMTableViewController.h"
|
||||
|
||||
@interface BookmarksVC : MWMTableViewController <LocationObserver, UITextFieldDelegate>
|
||||
@interface BookmarksVC : MWMTableViewController <UITextFieldDelegate>
|
||||
{
|
||||
size_t m_categoryIndex;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMBookmarkNameCell.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "Statistics.h"
|
||||
#import "UIColor+MapsMeColor.h"
|
||||
|
@ -25,7 +27,7 @@
|
|||
|
||||
extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotification";
|
||||
|
||||
@interface BookmarksVC() <MFMailComposeViewControllerDelegate>
|
||||
@interface BookmarksVC() <MFMailComposeViewControllerDelegate, MWMLocationObserver>
|
||||
{
|
||||
int m_trackSection;
|
||||
int m_bookmarkSection;
|
||||
|
@ -48,11 +50,6 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
return self;
|
||||
}
|
||||
|
||||
- (LocationManager *)locationManager
|
||||
{
|
||||
return [MapsAppDelegate theApp].locationManager;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
@ -162,17 +159,14 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
bmCell.textLabel.text = @(bm->GetName().c_str());
|
||||
bmCell.imageView.image = [CircleView createCircleImageWith:PINDIAMETER andColor:[ColorPickerView colorForName:@(bm->GetType().c_str())]];
|
||||
|
||||
// Get current position and compass "north" direction
|
||||
double azimut = -1.0;
|
||||
double lat, lon;
|
||||
|
||||
if ([self.locationManager getLat:lat Lon:lon])
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation)
|
||||
{
|
||||
double north = -1.0;
|
||||
[self.locationManager getNorthRad:north];
|
||||
|
||||
double north = location_helpers::headingToNorthRad([MWMLocationManager lastHeading]);
|
||||
string distance;
|
||||
fr.GetDistanceAndAzimut(bm->GetPivot(), lat, lon, north, distance, azimut);
|
||||
double azimut = -1.0;
|
||||
fr.GetDistanceAndAzimut(bm->GetPivot(), lastLocation.coordinate.latitude,
|
||||
lastLocation.coordinate.longitude, north, distance, azimut);
|
||||
|
||||
bmCell.detailTextLabel.text = @(distance.c_str());
|
||||
}
|
||||
|
@ -327,8 +321,8 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
}
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
//*********** Location manager callbacks ***************************
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
// Refresh distance
|
||||
|
@ -347,7 +341,7 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
m2::PointD const center = bm->GetPivot();
|
||||
double const metres = ms::DistanceOnEarth(info.m_latitude, info.m_longitude,
|
||||
MercatorBounds::YToLat(center.y), MercatorBounds::XToLon(center.x));
|
||||
cell.detailTextLabel.text = [LocationManager formattedDistance:metres];
|
||||
cell.detailTextLabel.text = location_helpers::formattedDistance(metres);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
@ -359,7 +353,7 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[self.locationManager start:self];
|
||||
[MWMLocationManager addObserver:self];
|
||||
|
||||
// Display Edit button only if table is not empty
|
||||
BookmarkCategory * cat = GetFramework().GetBmCategory(m_categoryIndex);
|
||||
|
@ -386,7 +380,8 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[self.locationManager stop:self];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
|
||||
// Save possibly edited set name
|
||||
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
if ([cell isKindOfClass:[MWMBookmarkNameCell class]])
|
||||
|
|
7
iphone/Maps/CLLocation+Mercator.h
Normal file
7
iphone/Maps/CLLocation+Mercator.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "geometry/point2d.hpp"
|
||||
|
||||
@interface CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator;
|
||||
|
||||
@end
|
8
iphone/Maps/CLLocation+Mercator.mm
Normal file
8
iphone/Maps/CLLocation+Mercator.mm
Normal file
|
@ -0,0 +1,8 @@
|
|||
#import "CLLocation+Mercator.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
|
||||
@implementation CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator { return location_helpers::ToMercator(self.coordinate); }
|
||||
|
||||
@end
|
|
@ -1,4 +1,3 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#import "MWMButton.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MWMSearchManager.h"
|
||||
#import "SettingsAndMoreVC.h"
|
||||
|
@ -293,8 +294,8 @@ typedef NS_ENUM(NSUInteger, MWMBottomMenuViewCell)
|
|||
{
|
||||
[Statistics logEvent:kStatMenu withParameters:@{kStatButton : kStatShare}];
|
||||
[Alohalytics logEvent:kAlohalyticsTapEventKey withValue:@"share@"];
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
if (!location)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
{
|
||||
[[[UIAlertView alloc] initWithTitle:L(@"unknown_current_position")
|
||||
message:nil
|
||||
|
@ -303,7 +304,7 @@ typedef NS_ENUM(NSUInteger, MWMBottomMenuViewCell)
|
|||
otherButtonTitles:nil] show];
|
||||
return;
|
||||
}
|
||||
CLLocationCoordinate2D const coord = location.coordinate;
|
||||
CLLocationCoordinate2D const coord = lastLocation.coordinate;
|
||||
NSIndexPath * cellIndex = [NSIndexPath indexPathForItem:MWMBottomMenuViewCellShare inSection:0];
|
||||
MWMBottomMenuCollectionViewCell * cell =
|
||||
(MWMBottomMenuCollectionViewCell *)[self.additionalButtons cellForItemAtIndexPath:cellIndex];
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#import "MWMButton.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MWMObjectsCategorySelectorController.h"
|
||||
#import "MWMPlacePageEntity.h"
|
||||
|
@ -90,9 +91,9 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
}
|
||||
else
|
||||
{
|
||||
LocationManager * m = MapsAppDelegate.theApp.locationManager;
|
||||
self.routeSource = m.lastLocationIsValid ? MWMRoutePoint(m.lastLocation.mercator)
|
||||
: MWMRoutePoint::MWMRoutePointZero();
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
self.routeSource =
|
||||
lastLocation ? MWMRoutePoint(lastLocation.mercator) : MWMRoutePoint::MWMRoutePointZero();
|
||||
}
|
||||
self.routeDestination = MWMRoutePoint::MWMRoutePointZero();
|
||||
}
|
||||
|
@ -383,8 +384,11 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
|
||||
- (void)restoreRouteTo:(m2::PointD const &)to
|
||||
{
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
auto & f = GetFramework();
|
||||
m2::PointD const myPosition = [MapsAppDelegate theApp].locationManager.lastLocation.mercator;
|
||||
m2::PointD const myPosition = lastLocation.mercator;
|
||||
f.SetRouter(f.GetBestRouter(myPosition, to));
|
||||
self.routeSource = MWMRoutePoint(myPosition);
|
||||
self.routeDestination = {to, @"Destination"};
|
||||
|
@ -498,8 +502,8 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
if (!self.isPossibleToBuildRoute)
|
||||
return;
|
||||
|
||||
LocationManager * locMgr = [MapsAppDelegate theApp].locationManager;
|
||||
if (!locMgr.lastLocation && self.routeSource.IsMyPosition())
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation && self.routeSource.IsMyPosition())
|
||||
{
|
||||
MWMAlertViewController * alert =
|
||||
[[MWMAlertViewController alloc] initWithViewController:self.ownerController];
|
||||
|
@ -507,14 +511,14 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
return;
|
||||
}
|
||||
|
||||
m2::PointD const locationPoint = locMgr.lastLocation.mercator;
|
||||
m2::PointD const locationPoint = lastLocation.mercator;
|
||||
if (self.routeSource.IsMyPosition())
|
||||
{
|
||||
[Statistics
|
||||
logEvent:kStatPointToPoint
|
||||
withParameters:@{kStatAction : kStatBuildRoute, kStatValue : kStatFromMyPosition}];
|
||||
self.routeSource = MWMRoutePoint(locationPoint);
|
||||
[locMgr start:self.navigationManager];
|
||||
[MWMLocationManager addObserver:self.navigationManager];
|
||||
}
|
||||
else if (self.routeDestination.IsMyPosition())
|
||||
{
|
||||
|
@ -567,9 +571,9 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
if (!isSourceMyPosition)
|
||||
{
|
||||
MWMAlertViewController * controller = [[MWMAlertViewController alloc] initWithViewController:self.ownerController];
|
||||
LocationManager * manager = MapsAppDelegate.theApp.locationManager;
|
||||
BOOL const needToRebuild = manager.lastLocationIsValid && !manager.isLocationPendingOrNoPosition && !isDestinationMyPosition;
|
||||
m2::PointD const locationPoint = manager.lastLocation.mercator;
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
BOOL const needToRebuild = lastLocation && !location_helpers::isMyPositionPendingOrNoPosition() && !isDestinationMyPosition;
|
||||
m2::PointD const locationPoint = lastLocation.mercator;
|
||||
[controller presentPoint2PointAlertWithOkBlock:^
|
||||
{
|
||||
self.routeSource = MWMRoutePoint(locationPoint);
|
||||
|
@ -596,7 +600,7 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
- (void)didCancelRouting
|
||||
{
|
||||
[Statistics logEvent:kStatEventName(kStatPointToPoint, kStatClose)];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self.navigationManager];
|
||||
[MWMLocationManager removeObserver:self.navigationManager];
|
||||
self.navigationManager.state = MWMNavigationDashboardStateHidden;
|
||||
self.disableStandbyOnRouteFollowing = NO;
|
||||
[MapsAppDelegate theApp].routingPlaneMode = MWMRoutingPlaneModeNone;
|
||||
|
@ -634,9 +638,9 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
|
||||
- (void)resetRoutingPoint
|
||||
{
|
||||
LocationManager * m = MapsAppDelegate.theApp.locationManager;
|
||||
self.routeSource = m.lastLocationIsValid ? MWMRoutePoint(m.lastLocation.mercator) :
|
||||
MWMRoutePoint::MWMRoutePointZero();
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
self.routeSource =
|
||||
lastLocation ? MWMRoutePoint(lastLocation.mercator) : MWMRoutePoint::MWMRoutePointZero();
|
||||
self.routeDestination = MWMRoutePoint::MWMRoutePointZero();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMConsole.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMNoMapsViewController.h"
|
||||
#import "MWMRoutingProtocol.h"
|
||||
#import "MWMSearchManager.h"
|
||||
|
@ -173,7 +173,7 @@ extern NSString * const kSearchStateKey = @"SearchStateKey";
|
|||
- (void)tapMyPositionFromHistory
|
||||
{
|
||||
MapsAppDelegate * a = MapsAppDelegate.theApp;
|
||||
MWMRoutePoint const p = MWMRoutePoint::MWMRoutePoint(a.locationManager.lastLocation.mercator);
|
||||
MWMRoutePoint const p = MWMRoutePoint::MWMRoutePoint([MWMLocationManager lastLocation].mercator);
|
||||
if (a.routingPlaneMode == MWMRoutingPlaneModeSearchSource)
|
||||
[self.delegate buildRouteFrom:p];
|
||||
else if (a.routingPlaneMode == MWMRoutingPlaneModeSearchDestination)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "Macros.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMSearchHistoryClearCell.h"
|
||||
#import "MWMSearchHistoryManager.h"
|
||||
#import "MWMSearchHistoryMyPositionCell.h"
|
||||
|
@ -27,9 +27,9 @@ static NSString * const kMyPositionCellIdentifier = @"MWMSearchHistoryMyPosition
|
|||
- (BOOL)isRouteSearchMode
|
||||
{
|
||||
MWMRoutingPlaneMode const m = MapsAppDelegate.theApp.routingPlaneMode;
|
||||
return (m == MWMRoutingPlaneModeSearchSource ||
|
||||
m == MWMRoutingPlaneModeSearchDestination) &&
|
||||
MapsAppDelegate.theApp.locationManager.lastLocationIsValid;
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
return lastLocation &&
|
||||
(m == MWMRoutingPlaneModeSearchSource || m == MWMRoutingPlaneModeSearchDestination);
|
||||
}
|
||||
|
||||
- (void)attachCell:(MWMSearchTabbedCollectionViewCell *)cell
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMSearchCommonCell.h"
|
||||
#import "UIColor+MapsMeColor.h"
|
||||
#import "UIFont+MapsMeFonts.h"
|
||||
|
@ -57,12 +57,10 @@
|
|||
if (result.HasPoint())
|
||||
{
|
||||
string distanceStr;
|
||||
double lat, lon;
|
||||
LocationManager * locationManager = MapsAppDelegate.theApp.locationManager;
|
||||
if ([locationManager getLat:lat Lon:lon])
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation)
|
||||
{
|
||||
m2::PointD const mercLoc = MercatorBounds::FromLatLon(lat, lon);
|
||||
double const dist = MercatorBounds::DistanceOnEarth(mercLoc, result.GetFeatureCenter());
|
||||
double const dist = MercatorBounds::DistanceOnEarth(lastLocation.mercator, result.GetFeatureCenter());
|
||||
MeasurementUtils::FormatDistance(dist, distanceStr);
|
||||
}
|
||||
self.distanceLabel.text = @(distanceStr.c_str());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "LocationManager.h"
|
||||
#import "Macros.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMSearchCommonCell.h"
|
||||
#import "MWMSearchShowOnMapCell.h"
|
||||
#import "MWMSearchSuggestionCell.h"
|
||||
|
@ -35,8 +35,7 @@ NSString * identifierForType(MWMSearchTableCellType type)
|
|||
}
|
||||
}
|
||||
|
||||
@interface MWMSearchTableViewController () <UITableViewDataSource, UITableViewDelegate,
|
||||
LocationObserver>
|
||||
@interface MWMSearchTableViewController () <UITableViewDataSource, UITableViewDelegate, MWMLocationObserver>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UITableView * tableView;
|
||||
|
||||
|
@ -292,7 +291,7 @@ forRowAtIndexPath:(NSIndexPath *)indexPath
|
|||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - LocationObserver
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
|
@ -360,9 +359,9 @@ forRowAtIndexPath:(NSIndexPath *)indexPath
|
|||
return;
|
||||
_watchLocationUpdates = watchLocationUpdates;
|
||||
if (watchLocationUpdates)
|
||||
[[MapsAppDelegate theApp].locationManager start:self];
|
||||
[MWMLocationManager addObserver:self];
|
||||
else
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
}
|
||||
|
||||
@synthesize searchOnMap = _searchOnMap;
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMFirstLaunchController.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMPageController.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
@interface MWMFirstLaunchController () <LocationObserver>
|
||||
@interface MWMLocationManager ()
|
||||
|
||||
@property (nonatomic) BOOL started;
|
||||
+ (MWMLocationManager *)manager;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMFirstLaunchController ()
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView * containerView;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView * image;
|
||||
|
@ -22,8 +29,6 @@
|
|||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * titleTopOffset;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * titleImageOffset;
|
||||
|
||||
@property (nonatomic) BOOL locationError;
|
||||
|
||||
@end
|
||||
|
||||
namespace
|
||||
|
@ -50,12 +55,11 @@ void zoomToCurrentPosition()
|
|||
{
|
||||
auto & f = GetFramework();
|
||||
f.SwitchMyPositionNextMode();
|
||||
LocationManager * locationManager = MapsAppDelegate.theApp.locationManager;
|
||||
if (![locationManager lastLocationIsValid])
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
m2::PointD const centerPt = locationManager.lastLocation.mercator;
|
||||
int const zoom = 13;
|
||||
f.SetViewportCenter(centerPt, zoom);
|
||||
f.SetViewportCenter(lastLocation.mercator, zoom);
|
||||
}
|
||||
|
||||
NSInteger constexpr kRequestLocationPage = 2;
|
||||
|
@ -117,16 +121,6 @@ NSArray<TMWMWelcomeConfigBlock> * pagesConfigBlocks = @[
|
|||
return pagesConfigBlocks;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
if (self.pageIndex == kRequestLocationPage)
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(appWillEnterForeground:)
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
@ -136,24 +130,9 @@ NSArray<TMWMWelcomeConfigBlock> * pagesConfigBlocks = @[
|
|||
requestNotifications();
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
if (self.locationError)
|
||||
[MapsAppDelegate.theApp.locationManager reset];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)requestLocation
|
||||
{
|
||||
MapsAppDelegate * app = MapsAppDelegate.theApp;
|
||||
LocationManager * lm = app.locationManager;
|
||||
[lm onForeground];
|
||||
[lm start:self];
|
||||
[MWMLocationManager manager].started = YES;
|
||||
}
|
||||
|
||||
- (void)close
|
||||
|
@ -162,23 +141,6 @@ NSArray<TMWMWelcomeConfigBlock> * pagesConfigBlocks = @[
|
|||
zoomToCurrentPosition();
|
||||
}
|
||||
|
||||
- (void)appWillEnterForeground:(NSNotification *)notification
|
||||
{
|
||||
[self requestLocation];
|
||||
}
|
||||
|
||||
#pragma mark - LocationManager Callbacks
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
}
|
||||
|
||||
- (void)onLocationError:(location::TLocationError)errorCode
|
||||
{
|
||||
if (errorCode == location::EDenied)
|
||||
self.locationError = YES;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setSize:(CGSize)size
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMNavigationDashboardEntity.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
@ -23,11 +23,12 @@ using namespace routing::turns;
|
|||
_targetUnits = @(info.m_targetUnitsSuffix.c_str());
|
||||
_progress = info.m_completionPercent;
|
||||
auto & f = GetFramework();
|
||||
if (f.GetRouter() == routing::RouterType::Pedestrian)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation && f.GetRouter() == routing::RouterType::Pedestrian)
|
||||
{
|
||||
_isPedestrian = YES;
|
||||
string distance;
|
||||
CLLocationCoordinate2D const & coordinate ([MapsAppDelegate theApp].locationManager.lastLocation.coordinate);
|
||||
CLLocationCoordinate2D const & coordinate = lastLocation.coordinate;
|
||||
ms::LatLon const & directionPos = info.m_pedestrianDirectionPos;
|
||||
//TODO: Not the best solution, but this solution is temporary and will be replaced in future
|
||||
MeasurementUtils::FormatDistance(ms::DistanceOnEarth(coordinate.latitude, coordinate.longitude,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMNavigationViewProtocol.h"
|
||||
#import "MWMRoutePreview.h"
|
||||
|
||||
|
@ -30,7 +30,7 @@ typedef NS_ENUM(NSUInteger, MWMNavigationDashboardState)
|
|||
|
||||
@class MWMNavigationDashboardEntity;
|
||||
|
||||
@interface MWMNavigationDashboardManager : NSObject <LocationObserver>
|
||||
@interface MWMNavigationDashboardManager : NSObject <MWMLocationObserver>
|
||||
|
||||
@property (nonatomic, readonly) MWMNavigationDashboardEntity * entity;
|
||||
@property (weak, nonatomic, readonly) MWMRoutePreview * routePreview;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#import "Macros.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLanesPanel.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMNavigationDashboard.h"
|
||||
#import "MWMNavigationDashboardEntity.h"
|
||||
#import "MWMNavigationDashboardManager.h"
|
||||
|
@ -432,23 +433,16 @@ extern NSString * const kTTSStatusWasChangedNotification;
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark - LocationObserver
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(const location::GpsInfo &)info
|
||||
{
|
||||
// We don't need information about location update in this class,
|
||||
// but in LocationObserver protocol this method is required
|
||||
// since we don't want runtime overhead for introspection.
|
||||
}
|
||||
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info
|
||||
- (void)onHeadingUpdate:(location::CompassInfo const &)info
|
||||
{
|
||||
auto & f = GetFramework();
|
||||
if (f.GetRouter() != routing::RouterType::Pedestrian)
|
||||
return;
|
||||
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
if (!location)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
|
||||
location::FollowingInfo res;
|
||||
|
@ -456,9 +450,10 @@ extern NSString * const kTTSStatusWasChangedNotification;
|
|||
if (!res.IsValid())
|
||||
return;
|
||||
|
||||
CGFloat const angle = ang::AngleTo(location.mercator,
|
||||
ToMercator(res.m_pedestrianDirectionPos)) + info.m_bearing;
|
||||
CGAffineTransform const transform (CGAffineTransformMakeRotation(M_PI_2 - angle));
|
||||
CGFloat const angle = ang::AngleTo(lastLocation.mercator,
|
||||
location_helpers::ToMercator(res.m_pedestrianDirectionPos)) +
|
||||
info.m_bearing;
|
||||
CGAffineTransform const transform(CGAffineTransformMakeRotation(M_PI_2 - angle));
|
||||
self.navigationDashboardPortrait.direction.transform = transform;
|
||||
self.navigationDashboardLandscape.direction.transform = transform;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#import "Common.h"
|
||||
#import "EAGLView.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MWMDirectionView.h"
|
||||
|
||||
#import "../Platform/opengl/iosOGLContextFactory.h"
|
||||
|
@ -64,7 +63,7 @@ double getExactDPI(double contentScaleFactor)
|
|||
{
|
||||
NSLog(@"EAGLView initWithCoder Started");
|
||||
self = [super initWithCoder:coder];
|
||||
if (self && !MapsAppDelegate.theApp.isDaemonMode)
|
||||
if (self)
|
||||
[self initialize];
|
||||
|
||||
NSLog(@"EAGLView initWithCoder Ended");
|
||||
|
@ -74,7 +73,6 @@ double getExactDPI(double contentScaleFactor)
|
|||
- (void)initialize
|
||||
{
|
||||
lastViewSize = CGRectZero;
|
||||
_widgetsManager = [[MWMMapWidgets alloc] init];
|
||||
|
||||
// Setup Layer Properties
|
||||
CAEAGLLayer * eaglLayer = (CAEAGLLayer *)self.layer;
|
||||
|
@ -92,8 +90,6 @@ double getExactDPI(double contentScaleFactor)
|
|||
- (void)createDrapeEngineWithWidth:(int)width height:(int)height
|
||||
{
|
||||
LOG(LINFO, ("EAGLView createDrapeEngine Started"));
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
|
||||
Framework::DrapeCreationParams p;
|
||||
p.m_surfaceWidth = width;
|
||||
|
@ -181,4 +177,11 @@ double getExactDPI(double contentScaleFactor)
|
|||
m_factory->CastFactory<iosOGLContextFactory>()->setPresentAvailable(available);
|
||||
}
|
||||
|
||||
- (MWMMapWidgets *)widgetsManager
|
||||
{
|
||||
if (!_widgetsManager)
|
||||
_widgetsManager = [[MWMMapWidgets alloc] init];
|
||||
return _widgetsManager;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "CLLocation+Mercator.h"
|
||||
#import "Common.h"
|
||||
#import "LocalNotificationManager.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMStorage.h"
|
||||
|
|
110
iphone/Maps/Classes/Location/MWMLocationHelpers.h
Normal file
110
iphone/Maps/Classes/Location/MWMLocationHelpers.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
#import "MWMLocationManager.h"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
#include "platform/measurement_utils.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
namespace location_helpers
|
||||
{
|
||||
static inline char const * getSpeedSymbol(CLLocationSpeed const & metersPerSecond)
|
||||
{
|
||||
// 0-1 m/s
|
||||
static char const * turtle = "\xF0\x9F\x90\xA2 ";
|
||||
// 1-2 m/s
|
||||
static char const * pedestrian = "\xF0\x9F\x9A\xB6 ";
|
||||
// 2-5 m/s
|
||||
static char const * tractor = "\xF0\x9F\x9A\x9C ";
|
||||
// 5-10 m/s
|
||||
static char const * bicycle = "\xF0\x9F\x9A\xB2 ";
|
||||
// 10-36 m/s
|
||||
static char const * car = "\xF0\x9F\x9A\x97 ";
|
||||
// 36-120 m/s
|
||||
static char const * train = "\xF0\x9F\x9A\x85 ";
|
||||
// 120-278 m/s
|
||||
static char const * airplane = "\xE2\x9C\x88\xEF\xB8\x8F ";
|
||||
// 278+
|
||||
static char const * rocket = "\xF0\x9F\x9A\x80 ";
|
||||
|
||||
if (metersPerSecond <= 1.)
|
||||
return turtle;
|
||||
else if (metersPerSecond <= 2.)
|
||||
return pedestrian;
|
||||
else if (metersPerSecond <= 5.)
|
||||
return tractor;
|
||||
else if (metersPerSecond <= 10.)
|
||||
return bicycle;
|
||||
else if (metersPerSecond <= 36.)
|
||||
return car;
|
||||
else if (metersPerSecond <= 120.)
|
||||
return train;
|
||||
else if (metersPerSecond <= 278.)
|
||||
return airplane;
|
||||
else
|
||||
return rocket;
|
||||
}
|
||||
|
||||
static inline NSString * formattedSpeedAndAltitude(CLLocation * location)
|
||||
{
|
||||
if (!location)
|
||||
return nil;
|
||||
string result;
|
||||
if (location.altitude)
|
||||
result = "\xE2\x96\xB2 " /* this is simple mountain symbol */ +
|
||||
MeasurementUtils::FormatAltitude(location.altitude);
|
||||
// Speed is actual only for just received location
|
||||
if (location.speed > 0. && [location.timestamp timeIntervalSinceNow] >= -2.0)
|
||||
{
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += getSpeedSymbol(location.speed) + MeasurementUtils::FormatSpeed(location.speed);
|
||||
}
|
||||
return result.empty() ? nil : @(result.c_str());
|
||||
}
|
||||
|
||||
static inline NSString * formattedDistance(double const & meters)
|
||||
{
|
||||
if (meters < 0.)
|
||||
return nil;
|
||||
|
||||
string s;
|
||||
MeasurementUtils::FormatDistance(meters, s);
|
||||
return @(s.c_str());
|
||||
}
|
||||
|
||||
static inline BOOL isMyPositionPendingOrNoPosition()
|
||||
{
|
||||
location::EMyPositionMode mode;
|
||||
if (!settings::Get(settings::kLocationStateMode, mode))
|
||||
return true;
|
||||
return mode == location::EMyPositionMode::PendingPosition ||
|
||||
mode == location::EMyPositionMode::NotFollowNoPosition;
|
||||
}
|
||||
|
||||
static inline BOOL isLocationProhibited()
|
||||
{
|
||||
auto const status = [MWMLocationManager lastLocationStatus];
|
||||
return status == location::TLocationError::EDenied || status == location::TLocationError::EGPSIsOff;
|
||||
}
|
||||
|
||||
static inline double headingToNorthRad(CLHeading * heading)
|
||||
{
|
||||
double north = -1.0;
|
||||
if (heading)
|
||||
{
|
||||
north = (heading.trueHeading < 0) ? heading.magneticHeading : heading.trueHeading;
|
||||
north = my::DegToRad(north);
|
||||
}
|
||||
return north;
|
||||
}
|
||||
|
||||
static inline ms::LatLon ToLatLon(m2::PointD const & p) { return MercatorBounds::ToLatLon(p); }
|
||||
|
||||
static inline m2::PointD ToMercator(CLLocationCoordinate2D const & l)
|
||||
{
|
||||
return MercatorBounds::FromLatLon(l.latitude, l.longitude);
|
||||
}
|
||||
|
||||
static inline m2::PointD ToMercator(ms::LatLon const & l) { return MercatorBounds::FromLatLon(l); }
|
||||
|
||||
} // namespace MWMLocationHelpers
|
35
iphone/Maps/Classes/Location/MWMLocationManager.h
Normal file
35
iphone/Maps/Classes/Location/MWMLocationManager.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#import "CLLocation+Mercator.h"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
|
||||
@protocol MWMLocationObserver <NSObject>
|
||||
|
||||
@optional
|
||||
- (void)onHeadingUpdate:(location::CompassInfo const &)compassinfo;
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo;
|
||||
- (void)onLocationError:(location::TLocationError)locationError;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMLocationManager : NSObject
|
||||
|
||||
+ (void)addObserver:(id<MWMLocationObserver>)observer;
|
||||
+ (void)removeObserver:(id<MWMLocationObserver>)observer;
|
||||
|
||||
+ (void)setMyPositionMode:(location::EMyPositionMode)mode;
|
||||
|
||||
+ (CLLocation *)lastLocation;
|
||||
+ (location::TLocationError)lastLocationStatus;
|
||||
+ (CLHeading *)lastHeading;
|
||||
|
||||
+ (void)applicationDidBecomeActive;
|
||||
+ (void)applicationWillResignActive;
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("call +manager instead")));
|
||||
- (instancetype)copy __attribute__((unavailable("call +manager instead")));
|
||||
- (instancetype)copyWithZone:(NSZone *)zone __attribute__((unavailable("call +manager instead")));
|
||||
+ (instancetype)alloc __attribute__((unavailable("call +manager instead")));
|
||||
+ (instancetype)allocWithZone:(struct _NSZone *)zone __attribute__((unavailable("call +manager instead")));
|
||||
+ (instancetype)new __attribute__((unavailable("call +manager instead")));
|
||||
|
||||
@end
|
555
iphone/Maps/Classes/Location/MWMLocationManager.mm
Normal file
555
iphone/Maps/Classes/Location/MWMLocationManager.mm
Normal file
|
@ -0,0 +1,555 @@
|
|||
#import "Common.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
#import "MWMController.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMLocationPredictor.h"
|
||||
#import "Statistics.h"
|
||||
|
||||
#import "3party/Alohalytics/src/alohalytics_objc.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
#include "map/gps_tracker.hpp"
|
||||
|
||||
#include "std/map.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using TObserver = id<MWMLocationObserver>;
|
||||
using TObservers = NSHashTable<__kindof TObserver>;
|
||||
|
||||
void runAsyncOnMainQueue(dispatch_block_t block)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), block);
|
||||
}
|
||||
|
||||
location::GpsInfo gpsInfoFromLocation(CLLocation * l)
|
||||
{
|
||||
location::GpsInfo info;
|
||||
info.m_source = location::EAppleNative;
|
||||
|
||||
info.m_latitude = l.coordinate.latitude;
|
||||
info.m_longitude = l.coordinate.longitude;
|
||||
info.m_timestamp = l.timestamp.timeIntervalSince1970;
|
||||
|
||||
if (l.horizontalAccuracy >= 0.0)
|
||||
info.m_horizontalAccuracy = l.horizontalAccuracy;
|
||||
|
||||
if (l.verticalAccuracy >= 0.0)
|
||||
{
|
||||
info.m_verticalAccuracy = l.verticalAccuracy;
|
||||
info.m_altitude = l.altitude;
|
||||
}
|
||||
|
||||
if (l.course >= 0.0)
|
||||
info.m_bearing = l.course;
|
||||
|
||||
if (l.speed >= 0.0)
|
||||
info.m_speed = l.speed;
|
||||
return info;
|
||||
}
|
||||
|
||||
location::CompassInfo compassInfoFromHeading(CLHeading * h)
|
||||
{
|
||||
location::CompassInfo info;
|
||||
if (h.trueHeading >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.trueHeading);
|
||||
else if (h.headingAccuracy >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.magneticHeading);
|
||||
return info;
|
||||
}
|
||||
|
||||
enum class GeoMode
|
||||
{
|
||||
Pending,
|
||||
InPosition,
|
||||
NotInPosition,
|
||||
FollowAndRotate,
|
||||
VehicleRouting,
|
||||
PedestrianRouting,
|
||||
BicycleRouting
|
||||
};
|
||||
|
||||
struct DesiredAccuracy
|
||||
{
|
||||
CLLocationAccuracy charging;
|
||||
CLLocationAccuracy battery;
|
||||
};
|
||||
|
||||
struct GeoModeSettings
|
||||
{
|
||||
CLLocationDistance distanceFilter;
|
||||
DesiredAccuracy accuracy;
|
||||
};
|
||||
|
||||
map<GeoMode, GeoModeSettings> const kGeoSettings{
|
||||
{GeoMode::Pending,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBestForNavigation}}},
|
||||
{GeoMode::InPosition,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::NotInPosition,
|
||||
{.distanceFilter = 5,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::FollowAndRotate,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::VehicleRouting,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::PedestrianRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::BicycleRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}}};
|
||||
|
||||
BOOL keepRunningInBackground()
|
||||
{
|
||||
bool const needGPSForTrackRecorder = GpsTracker::Instance().IsEnabled();
|
||||
if (needGPSForTrackRecorder)
|
||||
return YES;
|
||||
|
||||
auto const & f = GetFramework();
|
||||
bool const isRouteBuilt = f.IsRouteBuilt();
|
||||
bool const isRouteFinished = f.IsRouteFinished();
|
||||
bool const isRouteRebuildingOnly = f.IsRouteRebuildingOnly();
|
||||
bool const needGPSForRouting = ((isRouteBuilt || isRouteRebuildingOnly) && !isRouteFinished);
|
||||
if (needGPSForRouting)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
MWMAlertViewController * alertController()
|
||||
{
|
||||
UIWindow * window = UIApplication.sharedApplication.delegate.window;
|
||||
UIViewController * rootViewController = window.rootViewController;
|
||||
ASSERT([rootViewController isKindOfClass:[UINavigationController class]], ());
|
||||
UINavigationController * navigationController = static_cast<UINavigationController *>(rootViewController);
|
||||
UIViewController * topViewController = navigationController.topViewController;
|
||||
ASSERT([topViewController conformsToProtocol:@protocol(MWMController)], ());
|
||||
UIViewController<MWMController> * mwmController = static_cast<UIViewController<MWMController> *>(topViewController);
|
||||
return mwmController.alertController;
|
||||
}
|
||||
|
||||
void sendInfoToFramework(dispatch_block_t block)
|
||||
{
|
||||
MapsAppDelegate * delegate = static_cast<MapsAppDelegate *>(UIApplication.sharedApplication.delegate);
|
||||
if (delegate.isDrapeEngineCreated)
|
||||
{
|
||||
block();
|
||||
}
|
||||
else
|
||||
{
|
||||
runAsyncOnMainQueue(^
|
||||
{
|
||||
sendInfoToFramework(block);
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@interface MWMLocationManager () <CLLocationManagerDelegate>
|
||||
|
||||
@property (nonatomic) BOOL started;
|
||||
@property (nonatomic) CLLocationManager * locationManager;
|
||||
@property (nonatomic) GeoMode geoMode;
|
||||
@property (nonatomic) CLHeading * lastHeadingInfo;
|
||||
@property (nonatomic) CLLocation * lastLocationInfo;
|
||||
@property (nonatomic) location::TLocationError lastLocationStatus;
|
||||
@property (nonatomic) MWMLocationPredictor * predictor;
|
||||
@property (nonatomic) TObservers * observers;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMLocationManager
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
+ (MWMLocationManager *)manager
|
||||
{
|
||||
static MWMLocationManager * manager;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{ manager = [[super alloc] initManager]; });
|
||||
return manager;
|
||||
}
|
||||
|
||||
- (instancetype)initManager
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
_observers = [TObservers weakObjectsHashTable];
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Add/Remove Observers
|
||||
|
||||
+ (void)addObserver:(TObserver)observer
|
||||
{
|
||||
runAsyncOnMainQueue(^
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
[manager.observers addObject:observer];
|
||||
[manager processLocationUpdate:manager.lastLocationInfo];
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)removeObserver:(TObserver)observer
|
||||
{
|
||||
runAsyncOnMainQueue(^
|
||||
{
|
||||
[[MWMLocationManager manager].observers removeObject:observer];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - App Life Cycle
|
||||
|
||||
+ (void)applicationDidBecomeActive
|
||||
{
|
||||
if (![Alohalytics isFirstSession])
|
||||
[MWMLocationManager manager].started = YES;
|
||||
}
|
||||
|
||||
+ (void)applicationWillResignActive
|
||||
{
|
||||
BOOL const keepRunning = keepRunningInBackground();
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
CLLocationManager * locationManager = manager.locationManager;
|
||||
if ([locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
|
||||
[locationManager setAllowsBackgroundLocationUpdates:keepRunning];
|
||||
manager.started = keepRunning;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
+ (CLLocation *)lastLocation
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
if (!manager.started || !manager.lastLocationInfo ||
|
||||
manager.lastLocationInfo.horizontalAccuracy < 0 ||
|
||||
manager.lastLocationStatus != location::TLocationError::ENoError)
|
||||
return nil;
|
||||
return manager.lastLocationInfo;
|
||||
}
|
||||
|
||||
+ (location::TLocationError)lastLocationStatus
|
||||
{
|
||||
return [MWMLocationManager manager].lastLocationStatus;
|
||||
}
|
||||
|
||||
+ (CLHeading *)lastHeading
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
if (!manager.started || !manager.lastHeadingInfo || manager.lastHeadingInfo.headingAccuracy < 0)
|
||||
return nil;
|
||||
return manager.lastHeadingInfo;
|
||||
}
|
||||
|
||||
#pragma mark - Observer notifications
|
||||
|
||||
- (void)processLocationStatus:(location::TLocationError)locationError
|
||||
{
|
||||
// if (self.lastLocationStatus == locationError)
|
||||
// return;
|
||||
self.lastLocationStatus = locationError;
|
||||
sendInfoToFramework(^
|
||||
{
|
||||
if (self.lastLocationStatus != location::TLocationError::ENoError)
|
||||
GetFramework().OnLocationError(self.lastLocationStatus);
|
||||
});
|
||||
for (TObserver observer in self.observers)
|
||||
{
|
||||
if ([observer respondsToSelector:@selector(onLocationError:)])
|
||||
[observer onLocationError:self.lastLocationStatus];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)processHeadingUpdate:(CLHeading *)headingInfo
|
||||
{
|
||||
self.lastHeadingInfo = headingInfo;
|
||||
sendInfoToFramework(^
|
||||
{
|
||||
GetFramework().OnCompassUpdate(compassInfoFromHeading(self.lastHeadingInfo));
|
||||
});
|
||||
location::CompassInfo const compassInfo = compassInfoFromHeading(headingInfo);
|
||||
for (TObserver observer in self.observers)
|
||||
{
|
||||
if ([observer respondsToSelector:@selector(onHeadingUpdate:)])
|
||||
[observer onHeadingUpdate:compassInfo];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)processLocationUpdate:(CLLocation *)locationInfo
|
||||
{
|
||||
if (!locationInfo)
|
||||
return;
|
||||
location::GpsInfo const gpsInfo = gpsInfoFromLocation(locationInfo);
|
||||
[self onLocationUpdate:gpsInfo];
|
||||
if (self.lastLocationInfo == locationInfo)
|
||||
return;
|
||||
self.lastLocationInfo = locationInfo;
|
||||
self.lastLocationStatus = location::TLocationError::ENoError;
|
||||
[self.predictor reset:gpsInfo];
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo
|
||||
{
|
||||
GpsTracker::Instance().OnLocationUpdated(gpsInfo);
|
||||
sendInfoToFramework([gpsInfo]
|
||||
{
|
||||
GetFramework().OnLocationUpdate(gpsInfo);
|
||||
});
|
||||
for (TObserver observer in self.observers)
|
||||
{
|
||||
if ([observer respondsToSelector:@selector(onLocationUpdate:)])
|
||||
[observer onLocationUpdate:gpsInfo];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Location Status
|
||||
|
||||
- (void)setLastLocationStatus:(location::TLocationError)lastLocationStatus
|
||||
{
|
||||
_lastLocationStatus = lastLocationStatus;
|
||||
switch (lastLocationStatus)
|
||||
{
|
||||
case location::ENoError:
|
||||
break;
|
||||
case location::ENotSupported:
|
||||
[alertController() presentLocationServiceNotSupportedAlert];
|
||||
break;
|
||||
case location::EDenied:
|
||||
[alertController() presentLocationAlert];
|
||||
break;
|
||||
case location::EGPSIsOff:
|
||||
// iOS shows its own alert.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - My Position
|
||||
|
||||
+ (void)setMyPositionMode:(location::EMyPositionMode)mode
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
[manager.predictor setMyPositionMode:mode];
|
||||
[manager processLocationStatus:manager.lastLocationStatus];
|
||||
auto const & f = GetFramework();
|
||||
if (f.IsRoutingActive())
|
||||
{
|
||||
switch (f.GetRouter())
|
||||
{
|
||||
case routing::RouterType::Vehicle:
|
||||
manager.geoMode = GeoMode::VehicleRouting;
|
||||
break;
|
||||
case routing::RouterType::Pedestrian:
|
||||
manager.geoMode = GeoMode::PedestrianRouting;
|
||||
break;
|
||||
case routing::RouterType::Bicycle:
|
||||
manager.geoMode = GeoMode::BicycleRouting;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case location::EMyPositionMode::PendingPosition:
|
||||
manager.geoMode = GeoMode::Pending;
|
||||
break;
|
||||
case location::EMyPositionMode::NotFollowNoPosition:
|
||||
case location::EMyPositionMode::NotFollow:
|
||||
manager.geoMode = GeoMode::NotInPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::Follow:
|
||||
manager.geoMode = GeoMode::InPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::FollowAndRotate:
|
||||
manager.geoMode = GeoMode::FollowAndRotate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Prediction
|
||||
|
||||
- (MWMLocationPredictor *)predictor
|
||||
{
|
||||
if (!_predictor)
|
||||
{
|
||||
__weak MWMLocationManager * weakSelf = self;
|
||||
_predictor = [[MWMLocationPredictor alloc] initWithOnPredictionBlock:^(location::GpsInfo const & gpsInfo)
|
||||
{
|
||||
[weakSelf onLocationUpdate:gpsInfo];
|
||||
}];
|
||||
}
|
||||
return _predictor;
|
||||
}
|
||||
|
||||
#pragma mark - Device notifications
|
||||
|
||||
- (void)orientationChanged
|
||||
{
|
||||
self.locationManager.headingOrientation = (CLDeviceOrientation)[UIDevice currentDevice].orientation;
|
||||
}
|
||||
|
||||
- (void)batteryStateChangedNotification:(NSNotification *)notification
|
||||
{
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
#pragma mark - Location manager
|
||||
|
||||
- (void)setGeoMode:(GeoMode)geoMode
|
||||
{
|
||||
if (_geoMode == geoMode)
|
||||
return;
|
||||
_geoMode = geoMode;
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
switch (geoMode)
|
||||
{
|
||||
case GeoMode::Pending:
|
||||
case GeoMode::InPosition:
|
||||
case GeoMode::NotInPosition:
|
||||
case GeoMode::FollowAndRotate:
|
||||
locationManager.activityType = CLActivityTypeOther;
|
||||
break;
|
||||
case GeoMode::VehicleRouting:
|
||||
locationManager.activityType = CLActivityTypeAutomotiveNavigation;
|
||||
break;
|
||||
case GeoMode::PedestrianRouting:
|
||||
case GeoMode::BicycleRouting:
|
||||
locationManager.activityType = CLActivityTypeFitness;
|
||||
break;
|
||||
}
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
- (void)refreshGeoModeSettings
|
||||
{
|
||||
UIDeviceBatteryState const state = [UIDevice currentDevice].batteryState;
|
||||
BOOL const isCharging = (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull);
|
||||
GeoModeSettings const settings = kGeoSettings.at(self.geoMode);
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
locationManager.desiredAccuracy = isCharging ? settings.accuracy.charging : settings.accuracy.battery;
|
||||
locationManager.distanceFilter = settings.distanceFilter;
|
||||
}
|
||||
|
||||
- (CLLocationManager *)locationManager
|
||||
{
|
||||
if (!_locationManager)
|
||||
{
|
||||
_locationManager = [[CLLocationManager alloc] init];
|
||||
_locationManager.delegate = self;
|
||||
[self refreshGeoModeSettings];
|
||||
_locationManager.pausesLocationUpdatesAutomatically = YES;
|
||||
_locationManager.headingFilter = 3.0;
|
||||
}
|
||||
return _locationManager;
|
||||
}
|
||||
|
||||
#pragma mark - CLLocationManagerDelegate
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading
|
||||
{
|
||||
[self processHeadingUpdate:heading];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
|
||||
{
|
||||
CLLocation * location = locations.lastObject;
|
||||
// According to documentation, lat and lon are valid only if horizontalAccuracy is non-negative.
|
||||
// So we filter out such events completely.
|
||||
if (location.horizontalAccuracy < 0.)
|
||||
return;
|
||||
[self processLocationUpdate:location];
|
||||
[[Statistics instance] logLocation:location];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
if (self.lastLocationStatus == location::TLocationError::ENoError && error.code == kCLErrorDenied)
|
||||
[self processLocationStatus:location::EDenied];
|
||||
}
|
||||
|
||||
#pragma mark - Start / Stop
|
||||
|
||||
- (void)setStarted:(BOOL)started
|
||||
{
|
||||
if (_started == started)
|
||||
return;
|
||||
UIDevice * device = [UIDevice currentDevice];
|
||||
NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter];
|
||||
if (started)
|
||||
{
|
||||
_started = [self start];
|
||||
device.batteryMonitoringEnabled = YES;
|
||||
[notificationCenter addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[notificationCenter addObserver:self selector:@selector(batteryStateChangedNotification:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
_started = NO;
|
||||
[self stop];
|
||||
device.batteryMonitoringEnabled = NO;
|
||||
[notificationCenter removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[notificationCenter removeObserver:self name:UIDeviceBatteryStateDidChangeNotification object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)start
|
||||
{
|
||||
auto const doStart = ^
|
||||
{
|
||||
LOG(LINFO, ("startUpdatingLocation"));
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
|
||||
[locationManager requestWhenInUseAuthorization];
|
||||
[locationManager startUpdatingLocation];
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[locationManager startUpdatingHeading];
|
||||
};
|
||||
if ([CLLocationManager locationServicesEnabled])
|
||||
{
|
||||
switch ([CLLocationManager authorizationStatus])
|
||||
{
|
||||
case kCLAuthorizationStatusAuthorizedWhenInUse:
|
||||
case kCLAuthorizationStatusAuthorizedAlways:
|
||||
case kCLAuthorizationStatusNotDetermined:
|
||||
doStart();
|
||||
return YES;
|
||||
case kCLAuthorizationStatusRestricted:
|
||||
case kCLAuthorizationStatusDenied:
|
||||
[self processLocationStatus:location::EDenied];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call start to make iOS show its alert to request geo service.
|
||||
doStart();
|
||||
[self processLocationStatus:location::EGPSIsOff];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)stop
|
||||
{
|
||||
LOG(LINFO, ("stopUpdatingLocation"));
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
[locationManager stopUpdatingLocation];
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[locationManager stopUpdatingHeading];
|
||||
}
|
||||
|
||||
@end
|
13
iphone/Maps/Classes/Location/MWMLocationPredictor.h
Normal file
13
iphone/Maps/Classes/Location/MWMLocationPredictor.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#import "MWMTypes.h"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
|
||||
using TPredictionBlock = void (^)(location::GpsInfo const &);
|
||||
|
||||
@interface MWMLocationPredictor : NSObject
|
||||
|
||||
- (instancetype)initWithOnPredictionBlock:(TPredictionBlock)onPredictBlock;
|
||||
- (void)reset:(location::GpsInfo const &)info;
|
||||
- (void)setMyPositionMode:(location::EMyPositionMode)mode;
|
||||
|
||||
@end
|
81
iphone/Maps/Classes/Location/MWMLocationPredictor.mm
Normal file
81
iphone/Maps/Classes/Location/MWMLocationPredictor.mm
Normal file
|
@ -0,0 +1,81 @@
|
|||
#import "MWMLocationPredictor.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
NSTimeInterval constexpr kPredictionIntervalInSeconds = 0.5;
|
||||
NSUInteger constexpr kMaxPredictionCount = 20;
|
||||
} // namespace
|
||||
|
||||
@interface MWMLocationPredictor ()
|
||||
|
||||
@property (nonatomic) location::GpsInfo lastLocationInfo;
|
||||
@property (nonatomic) BOOL isLastLocationInfoValid;
|
||||
@property (nonatomic) BOOL isLastPositionModeValid;
|
||||
@property (nonatomic) NSUInteger predictionsCount;
|
||||
@property (copy, nonatomic) TPredictionBlock onPredictionBlock;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMLocationPredictor
|
||||
|
||||
- (instancetype)initWithOnPredictionBlock:(TPredictionBlock)onPredictionBlock
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
_onPredictionBlock = [onPredictionBlock copy];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMyPositionMode:(location::EMyPositionMode)mode
|
||||
{
|
||||
self.isLastPositionModeValid = (mode == location::FollowAndRotate);
|
||||
[self restart];
|
||||
}
|
||||
|
||||
- (void)reset:(location::GpsInfo const &)locationInfo
|
||||
{
|
||||
self.isLastLocationInfoValid = (locationInfo.HasSpeed() && locationInfo.HasBearing());
|
||||
if (self.isLastLocationInfoValid)
|
||||
self.lastLocationInfo = locationInfo;
|
||||
|
||||
[self restart];
|
||||
}
|
||||
|
||||
- (BOOL)isActive
|
||||
{
|
||||
return self.isLastLocationInfoValid && self.isLastPositionModeValid && self.predictionsCount < kMaxPredictionCount;
|
||||
}
|
||||
|
||||
- (void)restart
|
||||
{
|
||||
self.predictionsCount = 0;
|
||||
[self schedule];
|
||||
}
|
||||
|
||||
- (void)schedule
|
||||
{
|
||||
SEL const predict = @selector(predict);
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:predict object:nil];
|
||||
[self performSelector:predict withObject:nil afterDelay:kPredictionIntervalInSeconds];
|
||||
}
|
||||
|
||||
- (void)predict
|
||||
{
|
||||
if (!self.isActive)
|
||||
return;
|
||||
|
||||
self.predictionsCount++;
|
||||
|
||||
location::GpsInfo info = self.lastLocationInfo;
|
||||
info.m_source = location::EPredictor;
|
||||
info.m_timestamp = [NSDate date].timeIntervalSince1970;
|
||||
Framework::PredictLocation(info.m_latitude, info.m_longitude, info.m_horizontalAccuracy,
|
||||
info.m_bearing, info.m_speed,
|
||||
info.m_timestamp - self.lastLocationInfo.m_timestamp);
|
||||
self.onPredictionBlock(info);
|
||||
[self schedule];
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#import "../Platform/LocationManager.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface LocationPredictor : NSObject
|
||||
|
||||
-(id)initWithObserver:(NSObject<LocationObserver> *) observer;
|
||||
-(void)reset:(location::GpsInfo const &) info;
|
||||
-(void)setMode:(location::EMyPositionMode) mode;
|
||||
|
||||
@end
|
|
@ -1,106 +0,0 @@
|
|||
#import "LocationPredictor.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
#include "base/timer.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
NSTimeInterval const PREDICTION_INTERVAL = 0.2; // in seconds
|
||||
int const MAX_PREDICTION_COUNT = 20;
|
||||
}
|
||||
|
||||
@implementation LocationPredictor
|
||||
{
|
||||
NSObject<LocationObserver> * m_observer;
|
||||
NSTimer * m_timer;
|
||||
|
||||
location::GpsInfo m_lastGpsInfo;
|
||||
bool m_gpsInfoIsValid;
|
||||
|
||||
int m_connectionSlot;
|
||||
bool m_generatePredictions;
|
||||
int m_predictionCount;
|
||||
}
|
||||
|
||||
-(id)initWithObserver:(NSObject<LocationObserver> *)observer
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
m_observer = observer;
|
||||
m_timer = nil;
|
||||
m_gpsInfoIsValid = false;
|
||||
m_generatePredictions = false;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)setMode:(location::EMyPositionMode)mode
|
||||
{
|
||||
m_generatePredictions = (mode == location::FollowAndRotate);
|
||||
if (mode == location::PendingPosition || mode == location::NotFollowNoPosition)
|
||||
m_gpsInfoIsValid = false;
|
||||
|
||||
[self resetTimer];
|
||||
}
|
||||
|
||||
-(void)reset:(location::GpsInfo const &)info
|
||||
{
|
||||
if (info.HasSpeed() && info.HasBearing())
|
||||
{
|
||||
m_gpsInfoIsValid = true;
|
||||
m_lastGpsInfo = info;
|
||||
m_lastGpsInfo.m_timestamp = my::Timer::LocalTime();
|
||||
m_lastGpsInfo.m_source = location::EPredictor;
|
||||
}
|
||||
else
|
||||
m_gpsInfoIsValid = false;
|
||||
|
||||
[self resetTimer];
|
||||
}
|
||||
|
||||
-(bool)isPredict
|
||||
{
|
||||
return m_gpsInfoIsValid && m_generatePredictions;
|
||||
}
|
||||
|
||||
-(void)resetTimer
|
||||
{
|
||||
m_predictionCount = 0;
|
||||
|
||||
if (m_timer != nil)
|
||||
{
|
||||
[m_timer invalidate];
|
||||
m_timer = nil;
|
||||
}
|
||||
|
||||
if ([self isPredict])
|
||||
{
|
||||
m_timer = [NSTimer scheduledTimerWithTimeInterval:PREDICTION_INTERVAL
|
||||
target:self
|
||||
selector:@selector(timerFired)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)timerFired
|
||||
{
|
||||
if (![self isPredict])
|
||||
return;
|
||||
|
||||
if (m_predictionCount < MAX_PREDICTION_COUNT)
|
||||
{
|
||||
++m_predictionCount;
|
||||
|
||||
location::GpsInfo info = m_lastGpsInfo;
|
||||
info.m_timestamp = my::Timer::LocalTime();
|
||||
::Framework::PredictLocation(info.m_latitude, info.m_longitude, info.m_horizontalAccuracy, info.m_bearing,
|
||||
info.m_speed, info.m_timestamp - m_lastGpsInfo.m_timestamp);
|
||||
|
||||
[m_observer onLocationUpdate:info];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,10 +1,10 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMBasePlacePageView.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMPlacePage.h"
|
||||
#import "MWMPlacePageActionBar.h"
|
||||
#import "MWMPlacePageBookmarkCell.h"
|
||||
|
@ -257,7 +257,7 @@ using namespace storage;
|
|||
self.bookingRatingLabel.text = entity.bookingRating;
|
||||
self.bookingView.hidden = !entity.bookingPrice.length && !entity.bookingRating.length;
|
||||
BOOL const isHeadingAvaible = [CLLocationManager headingAvailable];
|
||||
BOOL const noLocation = MapsAppDelegate.theApp.locationManager.isLocationPendingOrNoPosition;
|
||||
BOOL const noLocation = location_helpers::isMyPositionPendingOrNoPosition();
|
||||
self.distanceLabel.hidden = noLocation || isMyPosition;
|
||||
BOOL const hideDirection = noLocation || isMyPosition || !isHeadingAvaible;
|
||||
self.directionArrow.hidden = hideDirection;
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MWMAPIBar.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMActivityViewController.h"
|
||||
#import "MWMAPIBar.h"
|
||||
#import "MWMBasePlacePageView.h"
|
||||
#import "MWMDirectionView.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMiPadPlacePage.h"
|
||||
#import "MWMiPhoneLandscapePlacePage.h"
|
||||
#import "MWMiPhonePortraitPlacePage.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMPlacePage.h"
|
||||
#import "MWMPlacePageActionBar.h"
|
||||
#import "MWMPlacePageEntity.h"
|
||||
#import "MWMPlacePageNavigationBar.h"
|
||||
#import "MWMPlacePageViewManager.h"
|
||||
#import "MWMPlacePageViewManagerDelegate.h"
|
||||
#import "MWMiPadPlacePage.h"
|
||||
#import "MWMiPhoneLandscapePlacePage.h"
|
||||
#import "MWMiPhonePortraitPlacePage.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "Statistics.h"
|
||||
|
||||
#import "3party/Alohalytics/src/alohalytics_objc.h"
|
||||
|
@ -27,7 +28,7 @@
|
|||
extern NSString * const kAlohalyticsTapEventKey;
|
||||
extern NSString * const kBookmarksChangedNotification;
|
||||
|
||||
@interface MWMPlacePageViewManager () <LocationObserver>
|
||||
@interface MWMPlacePageViewManager () <MWMLocationObserver>
|
||||
|
||||
@property (weak, nonatomic) MWMViewController * ownerViewController;
|
||||
@property (nonatomic, readwrite) MWMPlacePageEntity * entity;
|
||||
|
@ -61,14 +62,14 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
{
|
||||
[self.delegate placePageDidClose];
|
||||
[self.placePage dismiss];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
GetFramework().DeactivateMapSelection(false);
|
||||
self.placePage = nil;
|
||||
}
|
||||
|
||||
- (void)showPlacePage:(place_page::Info const &)info
|
||||
{
|
||||
[[MapsAppDelegate theApp].locationManager start:self];
|
||||
[MWMLocationManager addObserver:self];
|
||||
self.entity = [[MWMPlacePageEntity alloc] initWithInfo:info];
|
||||
if (IPAD)
|
||||
[self setPlacePageForiPad];
|
||||
|
@ -111,10 +112,8 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
- (void)configPlacePage
|
||||
{
|
||||
if (self.entity.isMyPosition)
|
||||
{
|
||||
BOOL hasSpeed;
|
||||
self.entity.subtitle = [[MapsAppDelegate theApp].locationManager formattedSpeedAndAltitude:hasSpeed];
|
||||
}
|
||||
self.entity.subtitle =
|
||||
location_helpers::formattedSpeedAndAltitude([MWMLocationManager lastLocation]);
|
||||
self.placePage.parentViewHeight = self.ownerViewController.view.height;
|
||||
[self.placePage configure];
|
||||
self.placePage.topBound = self.topBound;
|
||||
|
@ -147,11 +146,9 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
|
||||
- (void)updateMyPositionSpeedAndAltitude
|
||||
{
|
||||
if (!self.entity.isMyPosition)
|
||||
return;
|
||||
BOOL hasSpeed = NO;
|
||||
[self.placePage updateMyPositionStatus:[[MapsAppDelegate theApp].locationManager
|
||||
formattedSpeedAndAltitude:hasSpeed]];
|
||||
if (self.entity.isMyPosition)
|
||||
[self.placePage updateMyPositionStatus:location_helpers::formattedSpeedAndAltitude(
|
||||
[MWMLocationManager lastLocation])];
|
||||
}
|
||||
|
||||
- (void)setPlacePageForiPhoneWithOrientation:(UIInterfaceOrientation)orientation
|
||||
|
@ -188,9 +185,10 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
withParameters:@{kStatValue : kStatDestination}];
|
||||
[Alohalytics logEvent:kAlohalyticsTapEventKey withValue:@"ppRoute"];
|
||||
|
||||
LocationManager * lm = MapsAppDelegate.theApp.locationManager;
|
||||
[self.delegate buildRouteFrom:lm.isLocationPendingOrNoPosition ? MWMRoutePoint::MWMRoutePointZero()
|
||||
: MWMRoutePoint(lm.lastLocation.mercator)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
BOOL const noLocation = location_helpers::isMyPositionPendingOrNoPosition() || !lastLocation;
|
||||
[self.delegate buildRouteFrom:noLocation ? MWMRoutePoint::MWMRoutePointZero()
|
||||
: MWMRoutePoint(lastLocation.mercator)
|
||||
to:self.target];
|
||||
}
|
||||
|
||||
|
@ -249,8 +247,6 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
- (void)book:(BOOL)isDescription
|
||||
{
|
||||
NSMutableDictionary * stat = [@{kStatProvider : kStatBooking} mutableCopy];
|
||||
LocationManager * lm = MapsAppDelegate.theApp.locationManager;
|
||||
CLLocation * loc = lm.lastLocationIsValid ? lm.lastLocation : nil;
|
||||
MWMPlacePageEntity * en = self.entity;
|
||||
auto const latLon = en.latlon;
|
||||
stat[kStatHotel] = en.hotelId;
|
||||
|
@ -258,7 +254,7 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
stat[kStatHotelLon] = @(latLon.lon);
|
||||
[Statistics logEvent:isDescription ? kPlacePageHotelDetails : kPlacePageHotelBook
|
||||
withParameters:stat
|
||||
atLocation:loc];
|
||||
atLocation:[MWMLocationManager lastLocation]];
|
||||
|
||||
UIViewController * vc = static_cast<UIViewController *>(MapsAppDelegate.theApp.mapViewController);
|
||||
NSURL * url = isDescription ? [NSURL URLWithString:[self.entity getCellValue:MWMPlacePageCellTypeBookingMore]] : self.entity.bookingUrl;
|
||||
|
@ -353,12 +349,6 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
[self.delegate dragPlacePage:frame];
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
[self updateDistance];
|
||||
[self updateMyPositionSpeedAndAltitude];
|
||||
}
|
||||
|
||||
- (void)updateDistance
|
||||
{
|
||||
NSString * distance = [self distance];
|
||||
|
@ -368,33 +358,17 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
|
||||
- (NSString *)distance
|
||||
{
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
// TODO(AlexZ): Do we REALLY need this check? Why this method is called if user mark/m_info is empty?
|
||||
// TODO(AlexZ): Can location be checked before calling this method?
|
||||
if (!location/* || !m_userMark*/)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return @"";
|
||||
string distance;
|
||||
CLLocationCoordinate2D const coord = location.coordinate;
|
||||
CLLocationCoordinate2D const coord = lastLocation.coordinate;
|
||||
ms::LatLon const target = self.entity.latlon;
|
||||
MeasurementUtils::FormatDistance(ms::DistanceOnEarth(coord.latitude, coord.longitude,
|
||||
target.lat, target.lon), distance);
|
||||
return @(distance.c_str());
|
||||
}
|
||||
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info
|
||||
{
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
// TODO(AlexZ): Do we REALLY need this check? Why compass update is here if user mark/m_info is empty?
|
||||
// TODO(AlexZ): Can location be checked before calling this method?
|
||||
if (!location/* || !m_userMark*/)
|
||||
return;
|
||||
|
||||
CGFloat const angle = ang::AngleTo(location.mercator, self.entity.mercator) + info.m_bearing;
|
||||
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2 - angle);
|
||||
[self.placePage setDirectionArrowTransform:transform];
|
||||
[self.directionView setDirectionArrowTransform:transform];
|
||||
}
|
||||
|
||||
- (void)showDirectionViewWithTitle:(NSString *)title type:(NSString *)type
|
||||
{
|
||||
MWMDirectionView * directionView = self.directionView;
|
||||
|
@ -423,6 +397,25 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
((MWMiPadPlacePage *)self.placePage).height = height;
|
||||
}
|
||||
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onHeadingUpdate:(location::CompassInfo const &)info
|
||||
{
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
CGFloat const angle = ang::AngleTo(lastLocation.mercator, self.entity.mercator) + info.m_bearing;
|
||||
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2 - angle);
|
||||
[self.placePage setDirectionArrowTransform:transform];
|
||||
[self.directionView setDirectionArrowTransform:transform];
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)locationInfo
|
||||
{
|
||||
[self updateDistance];
|
||||
[self updateMyPositionSpeedAndAltitude];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (MWMDirectionView *)directionView
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloaderExtendedDataSource.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
@ -31,12 +31,12 @@ using namespace storage;
|
|||
|
||||
- (void)configNearMeSection
|
||||
{
|
||||
LocationManager * lm = MapsAppDelegate.theApp.locationManager;
|
||||
if (!lm.lastLocationIsValid)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
auto & countryInfoGetter = GetFramework().CountryInfoGetter();
|
||||
TCountriesVec closestCoutryIds;
|
||||
countryInfoGetter.GetRegionsCountryId(lm.lastLocation.mercator, closestCoutryIds);
|
||||
countryInfoGetter.GetRegionsCountryId(lastLocation.mercator, closestCoutryIds);
|
||||
NSMutableArray<NSString *> * nearmeCountries = [@[] mutableCopy];
|
||||
for (auto const & countryId : closestCoutryIds)
|
||||
[nearmeCountries addObject:@(countryId.c_str())];
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#import "LocationManager.h"
|
||||
#import "LocationPredictor.h"
|
||||
#import "MWMMapDownloaderTypes.h"
|
||||
#import "MWMViewController.h"
|
||||
#import <MyTargetSDKCorp/MTRGNativeAppwallAd.h>
|
||||
|
@ -13,19 +11,12 @@ namespace search { struct AddressInfo; }
|
|||
@class MWMMapViewControlsManager;
|
||||
@class MWMAPIBar;
|
||||
|
||||
@interface MapViewController : MWMViewController <LocationObserver>
|
||||
{
|
||||
LocationPredictor * m_predictor;
|
||||
}
|
||||
@interface MapViewController : MWMViewController
|
||||
|
||||
// called when app is terminated by system
|
||||
- (void)onTerminate;
|
||||
- (void)onEnterForeground;
|
||||
- (void)onEnterBackground;
|
||||
- (void)onGetFocus:(BOOL)isOnFocus;
|
||||
|
||||
- (void)setMapStyle:(MapStyle)mapStyle;
|
||||
|
||||
- (void)updateStatusBarStyle;
|
||||
|
||||
- (void)showAPIBar;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#import "MWMFirstLaunchController.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloadDialog.h"
|
||||
#import "MWMMapDownloaderViewController.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
|
@ -115,7 +117,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
|
||||
@interface MapViewController ()<MTRGNativeAppwallAdDelegate, MWMFrameworkRouteBuilderObserver,
|
||||
MWMFrameworkDrapeObserver, MWMFrameworkStorageObserver,
|
||||
MWMPageControllerProtocol>
|
||||
MWMPageControllerProtocol, MWMLocationObserver>
|
||||
|
||||
@property (nonatomic, readwrite) MWMMapViewControlsManager * controlsManager;
|
||||
@property (nonatomic) MWMBottomMenuState menuRestoreState;
|
||||
|
@ -133,45 +135,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
|
||||
@implementation MapViewController
|
||||
|
||||
#pragma mark - LocationManager Callbacks
|
||||
|
||||
- (void)onLocationError:(location::TLocationError)errorCode
|
||||
{
|
||||
GetFramework().OnLocationError(errorCode);
|
||||
|
||||
switch (errorCode)
|
||||
{
|
||||
case location::EDenied:
|
||||
{
|
||||
[self.alertController presentLocationAlert];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
break;
|
||||
}
|
||||
case location::ENotSupported:
|
||||
{
|
||||
[self.alertController presentLocationServiceNotSupportedAlert];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
if (info.m_source != location::EPredictor)
|
||||
[m_predictor reset:info];
|
||||
Framework & frm = GetFramework();
|
||||
frm.OnLocationUpdate(info);
|
||||
LOG_MEMORY_INFO();
|
||||
|
||||
[self updateRoutingInfo];
|
||||
|
||||
if (self.forceRoutingStateChange == ForceRoutingStateChangeRestoreRoute)
|
||||
[self restoreRoute];
|
||||
}
|
||||
|
||||
- (void)updateRoutingInfo
|
||||
{
|
||||
Framework & frm = GetFramework();
|
||||
|
@ -188,9 +151,14 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[[MWMTextToSpeech tts] playTurnNotifications];
|
||||
}
|
||||
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
GetFramework().OnCompassUpdate(info);
|
||||
[self updateRoutingInfo];
|
||||
|
||||
if (self.forceRoutingStateChange == ForceRoutingStateChangeRestoreRoute)
|
||||
[self restoreRoute];
|
||||
}
|
||||
|
||||
#pragma mark - Restore route
|
||||
|
@ -343,25 +311,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[(EAGLView *)self.view deallocateNative];
|
||||
}
|
||||
|
||||
- (void)onEnterBackground
|
||||
{
|
||||
// Save state and notify about entering background.
|
||||
GetFramework().EnterBackground();
|
||||
}
|
||||
|
||||
- (void)setMapStyle:(MapStyle)mapStyle
|
||||
{
|
||||
GetFramework().SetMapStyle(mapStyle);
|
||||
}
|
||||
|
||||
- (void)onEnterForeground
|
||||
{
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
// Notify about entering foreground (should be called on the first launch too).
|
||||
GetFramework().EnterForeground();
|
||||
}
|
||||
|
||||
- (void)onGetFocus:(BOOL)isOnFocus
|
||||
{
|
||||
[(EAGLView *)self.view setPresentAvailable:isOnFocus];
|
||||
|
@ -370,8 +319,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
|
||||
self.controlsManager.menuState = self.menuRestoreState;
|
||||
|
@ -382,6 +329,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
GetFramework().InvalidateRendering();
|
||||
[self showWelcomeScreenIfNeeded];
|
||||
[self showViralAlertIfNeeded];
|
||||
[MWMLocationManager addObserver:self];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
|
@ -393,8 +341,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
self.view.clipsToBounds = YES;
|
||||
[MTRGManager setMyCom:YES];
|
||||
[self processMyPositionStateModeEvent:location::PendingPosition];
|
||||
|
@ -460,6 +406,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[super viewWillDisappear:animated];
|
||||
self.menuRestoreState = self.controlsManager.menuState;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)presentViewController:(UIViewController *)viewControllerToPresent
|
||||
|
@ -502,7 +449,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
{
|
||||
NSLog(@"MapViewController initWithCoder Started");
|
||||
self = [super initWithCoder:coder];
|
||||
if (self && !MapsAppDelegate.theApp.isDaemonMode)
|
||||
if (self)
|
||||
[self initialize];
|
||||
|
||||
NSLog(@"MapViewController initWithCoder Ended");
|
||||
|
@ -524,7 +471,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[self processMyPositionStateModeEvent:mode];
|
||||
});
|
||||
|
||||
m_predictor = [[LocationPredictor alloc] initWithObserver:self];
|
||||
self.forceRoutingStateChange = ForceRoutingStateChangeNone;
|
||||
self.userTouchesAction = UserTouchesActionNone;
|
||||
self.menuRestoreState = MWMBottomMenuStateInactive;
|
||||
|
@ -566,49 +512,35 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
|
||||
- (void)processMyPositionStateModeEvent:(location::EMyPositionMode)mode
|
||||
{
|
||||
[m_predictor setMode:mode];
|
||||
|
||||
LocationManager * lm = [MapsAppDelegate theApp].locationManager;
|
||||
[lm processMyPositionStateModeEvent:mode];
|
||||
[MWMLocationManager setMyPositionMode:mode];
|
||||
[self.controlsManager processMyPositionStateModeEvent:mode];
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
switch (mode)
|
||||
{
|
||||
case location::PendingPosition:
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
[lm start:self];
|
||||
break;
|
||||
case location::NotFollowNoPosition:
|
||||
if (gIsFirstMyPositionMode && ![Alohalytics isFirstSession])
|
||||
case location::NotFollowNoPosition:
|
||||
if (gIsFirstMyPositionMode && ![Alohalytics isFirstSession])
|
||||
{
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL const isMapVisible = (self.navigationController.visibleViewController == self);
|
||||
if (isMapVisible && !location_helpers::isLocationProhibited())
|
||||
{
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
BOOL const isMapVisible = (self.navigationController.visibleViewController == self);
|
||||
if (isMapVisible && lm.isStarted)
|
||||
[self.alertController presentLocationNotFoundAlertWithOkBlock:^
|
||||
{
|
||||
[lm stop:self];
|
||||
BOOL const isLocationProhibited =
|
||||
lm.lastLocationError == location::TLocationError::EDenied ||
|
||||
lm.lastLocationError == location::TLocationError::EGPSIsOff;
|
||||
if (!isLocationProhibited)
|
||||
{
|
||||
[self.alertController presentLocationNotFoundAlertWithOkBlock:^
|
||||
{
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}];
|
||||
}
|
||||
}
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case location::NotFollow:
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
break;
|
||||
case location::Follow:
|
||||
case location::FollowAndRotate:
|
||||
self.disableStandbyOnLocationStateMode = YES;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case location::PendingPosition:
|
||||
case location::NotFollow:
|
||||
break;
|
||||
case location::Follow:
|
||||
case location::FollowAndRotate:
|
||||
self.disableStandbyOnLocationStateMode = YES;
|
||||
break;
|
||||
}
|
||||
gIsFirstMyPositionMode = NO;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ typedef NS_ENUM(NSUInteger, MWMRoutingPlaneMode)
|
|||
@property (nonatomic) MWMRoutingPlaneMode routingPlaneMode;
|
||||
|
||||
@property (nonatomic, readonly) MapViewController * mapViewController;
|
||||
@property (nonatomic, readonly) LocationManager * locationManager;
|
||||
@property (nonatomic, readonly) BOOL isDaemonMode;
|
||||
@property (nonatomic, readonly) BOOL isDrapeEngineCreated;
|
||||
|
||||
+ (MapsAppDelegate *)theApp;
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#import "Common.h"
|
||||
#import "EAGLView.h"
|
||||
#import "LocalNotificationManager.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
|
@ -10,6 +9,7 @@
|
|||
#import "MWMController.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMStorage.h"
|
||||
#import "MWMTextToSpeech.h"
|
||||
#import "Preferences.h"
|
||||
|
@ -140,7 +140,6 @@ using namespace osm_auth_ios;
|
|||
@property (weak, nonatomic) NSTimer * mapStyleSwitchTimer;
|
||||
|
||||
@property (nonatomic, readwrite) LocationManager * locationManager;
|
||||
@property (nonatomic, readwrite) BOOL isDaemonMode;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -214,9 +213,14 @@ using namespace osm_auth_ios;
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isDrapeEngineCreated
|
||||
{
|
||||
return ((EAGLView *)self.mapViewController.view).drapeEngineCreated;
|
||||
}
|
||||
|
||||
- (void)handleURLs
|
||||
{
|
||||
if (!((EAGLView *)self.mapViewController.view).drapeEngineCreated)
|
||||
if (!self.isDrapeEngineCreated)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{ [self handleURLs]; });
|
||||
return;
|
||||
|
@ -347,35 +351,40 @@ using namespace osm_auth_ios;
|
|||
{
|
||||
NSAssert([MapsAppDelegate isAutoNightMode], @"Invalid auto switcher's state");
|
||||
auto & f = GetFramework();
|
||||
MapsAppDelegate * app = MapsAppDelegate.theApp;
|
||||
CLLocation * l = app.locationManager.lastLocation;
|
||||
if (!l || !f.IsRoutingActive())
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation || !f.IsRoutingActive())
|
||||
return;
|
||||
dispatch_async(dispatch_get_main_queue(), [&f, l, self, app]
|
||||
CLLocationCoordinate2D const coord = lastLocation.coordinate;
|
||||
dispatch_async(dispatch_get_main_queue(), [coord]
|
||||
{
|
||||
auto const dayTime = GetDayTime(static_cast<time_t>(NSDate.date.timeIntervalSince1970), l.coordinate.latitude, l.coordinate.longitude);
|
||||
id<MWMController> vc = static_cast<id<MWMController>>(app.mapViewController.navigationController.topViewController);
|
||||
auto & f = GetFramework();
|
||||
MapsAppDelegate * app = MapsAppDelegate.theApp;
|
||||
auto const dayTime =
|
||||
GetDayTime(static_cast<time_t>(NSDate.date.timeIntervalSince1970),
|
||||
coord.latitude, coord.longitude);
|
||||
id<MWMController> vc = static_cast<id<MWMController>>(
|
||||
app.mapViewController.navigationController.topViewController);
|
||||
auto style = f.GetMapStyle();
|
||||
switch (dayTime)
|
||||
{
|
||||
case DayTimeType::Day:
|
||||
case DayTimeType::PolarDay:
|
||||
if (style != MapStyleClear && style != MapStyleLight)
|
||||
{
|
||||
f.SetMapStyle(MapStyleClear);
|
||||
[UIColor setNightMode:NO];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
case DayTimeType::Night:
|
||||
case DayTimeType::PolarNight:
|
||||
if (style != MapStyleDark)
|
||||
{
|
||||
f.SetMapStyle(MapStyleDark);
|
||||
[UIColor setNightMode:YES];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
case DayTimeType::Day:
|
||||
case DayTimeType::PolarDay:
|
||||
if (style != MapStyleClear && style != MapStyleLight)
|
||||
{
|
||||
f.SetMapStyle(MapStyleClear);
|
||||
[UIColor setNightMode:NO];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
case DayTimeType::Night:
|
||||
case DayTimeType::PolarNight:
|
||||
if (style != MapStyleDark)
|
||||
{
|
||||
f.SetMapStyle(MapStyleDark);
|
||||
[UIColor setNightMode:YES];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -386,11 +395,6 @@ using namespace osm_auth_ios;
|
|||
|
||||
// Initialize all 3party engines.
|
||||
BOOL returnValue = [self initStatistics:application didFinishLaunchingWithOptions:launchOptions];
|
||||
if (launchOptions[UIApplicationLaunchOptionsLocationKey])
|
||||
{
|
||||
self.isDaemonMode = YES;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
// We send Alohalytics installation id to Fabric.
|
||||
// To make sure id is created, ConfigCrashTrackers must be called after Statistics initialization.
|
||||
|
@ -407,8 +411,7 @@ using namespace osm_auth_ios;
|
|||
InitLocalizedStrings();
|
||||
[self determineMapStyle];
|
||||
|
||||
[self.mapViewController onEnterForeground];
|
||||
self.isDaemonMode = NO;
|
||||
GetFramework().EnterForeground();
|
||||
|
||||
[self initPushNotificationsWithLaunchOptions:launchOptions];
|
||||
[self commonInit];
|
||||
|
@ -531,16 +534,13 @@ using namespace osm_auth_ios;
|
|||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application
|
||||
{
|
||||
[self.locationManager beforeTerminate];
|
||||
[self.mapViewController onTerminate];
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
LOG(LINFO, ("applicationDidEnterBackground"));
|
||||
[self.locationManager stop:self.mapViewController];
|
||||
[self.locationManager onBackground];
|
||||
[self.mapViewController onEnterBackground];
|
||||
GetFramework().EnterBackground();
|
||||
if (m_activeDownloadsCounter)
|
||||
{
|
||||
m_backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
|
||||
|
@ -579,42 +579,25 @@ using namespace osm_auth_ios;
|
|||
[self.mapViewController.appWallAd close];
|
||||
[RouteState save];
|
||||
GetFramework().SetRenderingEnabled(false);
|
||||
[MWMLocationManager applicationWillResignActive];
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
{
|
||||
LOG(LINFO, ("applicationWillEnterForeground"));
|
||||
BOOL const needInit = self.isDaemonMode;
|
||||
self.isDaemonMode = NO;
|
||||
if (needInit)
|
||||
{
|
||||
[self.mapViewController initialize];
|
||||
[(EAGLView *)self.mapViewController.view initialize];
|
||||
[self.mapViewController.view setNeedsLayout];
|
||||
[self.mapViewController.view layoutIfNeeded];
|
||||
[self commonInit];
|
||||
[self incrementSessionsCountAndCheckForAlert];
|
||||
}
|
||||
[self.mapViewController onEnterForeground];
|
||||
GetFramework().EnterForeground();
|
||||
[MWMTextToSpeech activateAudioSession];
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
if (application.applicationState == UIApplicationStateBackground)
|
||||
{
|
||||
LOG(LINFO, ("applicationDidBecomeActive, applicationState = UIApplicationStateBackground"));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(LINFO, ("applicationDidBecomeActive"));
|
||||
[self.mapViewController onGetFocus: YES];
|
||||
[self handleURLs];
|
||||
[self restoreRouteState];
|
||||
[[Statistics instance] applicationDidBecomeActive];
|
||||
GetFramework().SetRenderingEnabled(true);
|
||||
if (![Alohalytics isFirstSession])
|
||||
[self.locationManager start:self.mapViewController];
|
||||
[MWMLocationManager applicationDidBecomeActive];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
@ -674,7 +657,7 @@ using namespace osm_auth_ios;
|
|||
|
||||
- (void)setMapStyle:(MapStyle)mapStyle
|
||||
{
|
||||
[self.mapViewController setMapStyle: mapStyle];
|
||||
GetFramework().SetMapStyle(mapStyle);
|
||||
}
|
||||
|
||||
+ (NSDictionary *)navigationBarTextAttributes
|
||||
|
@ -829,33 +812,6 @@ using namespace osm_auth_ios;
|
|||
return [(UINavigationController *)self.window.rootViewController viewControllers].firstObject;
|
||||
}
|
||||
|
||||
- (LocationManager *)locationManager
|
||||
{
|
||||
if (!_locationManager)
|
||||
_locationManager = [[LocationManager alloc] init];
|
||||
return _locationManager;
|
||||
}
|
||||
|
||||
@synthesize isDaemonMode = _isDaemonMode;
|
||||
|
||||
- (BOOL)isDaemonMode
|
||||
{
|
||||
if ([Alohalytics isFirstSession])
|
||||
return NO;
|
||||
return _isDaemonMode;
|
||||
}
|
||||
|
||||
- (void)setIsDaemonMode:(BOOL)isDaemonMode
|
||||
{
|
||||
if ([Alohalytics isFirstSession] && _isDaemonMode == isDaemonMode)
|
||||
return;
|
||||
_isDaemonMode = isDaemonMode;
|
||||
if (isDaemonMode)
|
||||
[self.locationManager onDaemonMode];
|
||||
else
|
||||
[self.locationManager onForeground];
|
||||
}
|
||||
|
||||
#pragma mark - Route state
|
||||
|
||||
- (void)restoreRouteState
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloaderViewController.h"
|
||||
#import "MWMMigrationView.h"
|
||||
#import "MWMMigrationViewController.h"
|
||||
|
@ -64,10 +64,11 @@ using namespace storage;
|
|||
[Statistics logEvent:kStatDownloaderMigrationStarted
|
||||
withParameters:@{kStatType : limited ? kStatCurrentMap : kStatAllMaps}];
|
||||
auto & f = GetFramework();
|
||||
LocationManager * lm = [MapsAppDelegate theApp].locationManager;
|
||||
ms::LatLon position{};
|
||||
if (![lm getLat:position.lat Lon:position.lon])
|
||||
position = MercatorBounds::ToLatLon(f.GetViewportCenter());
|
||||
|
||||
ms::LatLon position = MercatorBounds::ToLatLon(f.GetViewportCenter());
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation)
|
||||
position = ms::LatLon(lastLocation.coordinate.latitude, lastLocation.coordinate.longitude);
|
||||
|
||||
auto migrate = ^
|
||||
{
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloadDialog.h"
|
||||
#import "MWMStorage.h"
|
||||
#import "Statistics.h"
|
||||
|
@ -27,13 +27,13 @@ BOOL canAutoDownload(TCountryId const & countryId)
|
|||
(void)settings::Get(kAutoDownloadEnabledKey, autoDownloadEnabled);
|
||||
if (!autoDownloadEnabled)
|
||||
return NO;
|
||||
LocationManager * locationManager = MapsAppDelegate.theApp.locationManager;
|
||||
if (![locationManager lastLocationIsValid])
|
||||
return NO;
|
||||
if (GetPlatform().ConnectionStatus() != Platform::EConnectionType::CONNECTION_WIFI)
|
||||
return NO;
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return NO;
|
||||
auto const & countryInfoGetter = GetFramework().CountryInfoGetter();
|
||||
if (countryId != countryInfoGetter.GetRegionCountryId(locationManager.lastLocation.mercator))
|
||||
if (countryId != countryInfoGetter.GetRegionCountryId(lastLocation.mercator))
|
||||
return NO;
|
||||
return !platform::migrate::NeedMigrate();
|
||||
}
|
||||
|
|
|
@ -144,8 +144,8 @@
|
|||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>#description#</string>
|
||||
<key>UIApplicationShortcutItems</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
|
|
@ -97,6 +97,8 @@
|
|||
343FAC4B1CBFBDFC00A45D3B /* MWMNoMapsView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 343FAC491CBFBDFC00A45D3B /* MWMNoMapsView.mm */; };
|
||||
34479C7C1C60C6130065D261 /* MWMFrameworkListener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34479C781C60C6130065D261 /* MWMFrameworkListener.mm */; };
|
||||
34479C7D1C60C6130065D261 /* MWMFrameworkListener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34479C781C60C6130065D261 /* MWMFrameworkListener.mm */; };
|
||||
344D77B41D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */; };
|
||||
344D77B51D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */; };
|
||||
34570A391B13219600E6D4FD /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97C98653186C5F0500AF7E9E /* AudioToolbox.framework */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
34570A3B1B13222600E6D4FD /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 34570A3A1B13222600E6D4FD /* libz.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
34570A3D1B13223000E6D4FD /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 34570A3C1B13223000E6D4FD /* libsqlite3.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
|
@ -288,6 +290,7 @@
|
|||
34D349FC1CD0A3EE00895216 /* MWMWhatsNewEditorController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34D349FA1CD0A3EE00895216 /* MWMWhatsNewEditorController.mm */; };
|
||||
34D37E171CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34D37E161CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm */; };
|
||||
34D37E181CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34D37E161CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm */; };
|
||||
34D866DE1D213E8B00B593F8 /* MWMLocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */; };
|
||||
34DCDE3A1C75CD8100652CAC /* Framework.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34479C751C60C6130065D261 /* Framework.cpp */; };
|
||||
34DCDE3B1C75CE1F00652CAC /* MWMOpeningHoursDeleteScheduleTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 347FD85A1C60B2CE002FB65E /* MWMOpeningHoursDeleteScheduleTableViewCell.mm */; };
|
||||
34DDD5341BFDB0B600407F2F /* MWMMapDownloaderViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 342AF0DF1BE24E9A0016F3AE /* MWMMapDownloaderViewController.mm */; };
|
||||
|
@ -317,6 +320,9 @@
|
|||
34F9FB921C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 34F9FB8F1C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib */; };
|
||||
34F9FB931C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 34F9FB8F1C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib */; };
|
||||
34FE4C451BCC013500066718 /* MWMMapWidgets.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FE4C441BCC013500066718 /* MWMMapWidgets.mm */; };
|
||||
34FED54D1D1D45B900183B1B /* MWMLocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */; };
|
||||
34FED5501D21121000183B1B /* CLLocation+Mercator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */; };
|
||||
34FED5511D21121000183B1B /* CLLocation+Mercator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */; };
|
||||
4519503A1B7A3E070085DA05 /* patterns.txt in Resources */ = {isa = PBXBuildFile; fileRef = 451950391B7A3E070085DA05 /* patterns.txt */; };
|
||||
452FCA3B1B6A3DF7007019AB /* colors.txt in Resources */ = {isa = PBXBuildFile; fileRef = 452FCA3A1B6A3DF7007019AB /* colors.txt */; };
|
||||
46F26C7310F61FD600ECCA39 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46F26C7210F61FD600ECCA39 /* OpenGLES.framework */; };
|
||||
|
@ -448,7 +454,6 @@
|
|||
6741A9B81BF340DE002C974C /* MapViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = EED10A4411F78D120095FAD4 /* MapViewController.mm */; };
|
||||
6741A9B91BF340DE002C974C /* MWMRateAlert.mm in Sources */ = {isa = PBXBuildFile; fileRef = F61579331AC2CE9A0032D8E9 /* MWMRateAlert.mm */; };
|
||||
6741A9BA1BF340DE002C974C /* MWMRoutePointCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F6BB6CC51BB18C0900DF1DF2 /* MWMRoutePointCell.m */; };
|
||||
6741A9BB1BF340DE002C974C /* LocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */; };
|
||||
6741A9BE1BF340DE002C974C /* UILabel+RuntimeAttributes.mm in Sources */ = {isa = PBXBuildFile; fileRef = F62404FA1AAF3DB200B58DB6 /* UILabel+RuntimeAttributes.mm */; };
|
||||
6741A9BF1BF340DE002C974C /* MWMSearchTabbedCollectionViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34CC4C0C1B82069C00E44C1F /* MWMSearchTabbedCollectionViewCell.mm */; };
|
||||
6741A9C01BF340DE002C974C /* MWMTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6588E2B1B15C26700EE1E58 /* MWMTextView.mm */; };
|
||||
|
@ -486,7 +491,6 @@
|
|||
6741A9E91BF340DE002C974C /* Preferences.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA29FDA9141E77F8004ADF66 /* Preferences.mm */; };
|
||||
6741A9EB1BF340DE002C974C /* ContextViews.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6D409F91B319BD70041730F /* ContextViews.mm */; };
|
||||
6741A9EC1BF340DE002C974C /* MWMCircularProgress.mm in Sources */ = {isa = PBXBuildFile; fileRef = 349A35761B53D4C9009677EE /* MWMCircularProgress.mm */; };
|
||||
6741A9ED1BF340DE002C974C /* LocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAA5C2A1144F135F005337F6 /* LocationManager.mm */; };
|
||||
6741A9EE1BF340DE002C974C /* MWMSearchCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34B82AD91B847FFC00180497 /* MWMSearchCell.mm */; };
|
||||
6741A9EF1BF340DE002C974C /* MWMiPadPlacePage.mm in Sources */ = {isa = PBXBuildFile; fileRef = F66A8FAB1B09F137001B9C97 /* MWMiPadPlacePage.mm */; };
|
||||
6741A9F01BF340DE002C974C /* SettingsViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 978F9239183B660F000D6C7C /* SettingsViewController.mm */; };
|
||||
|
@ -653,7 +657,6 @@
|
|||
A32B6D4C1A14980500E54A65 /* iosOGLContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = A32B6D491A14980500E54A65 /* iosOGLContext.mm */; };
|
||||
A32B6D4D1A14980500E54A65 /* iosOGLContextFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = A32B6D4B1A14980500E54A65 /* iosOGLContextFactory.mm */; };
|
||||
A367C93B1B17334800E2B6E7 /* resources-default in Resources */ = {isa = PBXBuildFile; fileRef = A367C93A1B17334800E2B6E7 /* resources-default */; };
|
||||
A3CC2CD41A1C723900B832E1 /* LocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */; };
|
||||
B00510FB1A11015900A61AA4 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 972CDCC51887F1B7006641CA /* CFNetwork.framework */; };
|
||||
B00511021A1101E000A61AA4 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97C98655186C734000AF7E9E /* AVFoundation.framework */; };
|
||||
B00511041A1101F600A61AA4 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B00511031A1101F600A61AA4 /* CoreData.framework */; };
|
||||
|
@ -837,7 +840,6 @@
|
|||
FA85F633145DDDC20090E1A0 /* packed_polygons.bin in Resources */ = {isa = PBXBuildFile; fileRef = FA85F632145DDDC20090E1A0 /* packed_polygons.bin */; };
|
||||
FA87151B12B1518F00592DAF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA87151A12B1518F00592DAF /* SystemConfiguration.framework */; };
|
||||
FA99CB73147089B100689A9A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA99CB71147089B100689A9A /* Localizable.strings */; };
|
||||
FAA5C2A2144F135F005337F6 /* LocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAA5C2A1144F135F005337F6 /* LocationManager.mm */; };
|
||||
FAA614B8155F16950031C345 /* AddSetVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAA614B7155F16950031C345 /* AddSetVC.mm */; };
|
||||
FAAEA7D1161BD26600CCD661 /* synonyms.txt in Resources */ = {isa = PBXBuildFile; fileRef = FAAEA7D0161BD26600CCD661 /* synonyms.txt */; };
|
||||
FAAEA7D5161D8D3100CCD661 /* BookmarksRootVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAAEA7D3161D8D3100CCD661 /* BookmarksRootVC.mm */; };
|
||||
|
@ -991,6 +993,8 @@
|
|||
34479C781C60C6130065D261 /* MWMFrameworkListener.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMFrameworkListener.mm; sourceTree = "<group>"; };
|
||||
34479C791C60C6130065D261 /* MWMFrameworkObservers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkObservers.h; sourceTree = "<group>"; };
|
||||
344BDB021B9069810076DB31 /* MWMSearchTabbedViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMSearchTabbedViewProtocol.h; sourceTree = "<group>"; };
|
||||
344D77B21D1BD7C800DBED70 /* MWMLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMLocationManager.h; sourceTree = "<group>"; };
|
||||
344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMLocationManager.mm; sourceTree = "<group>"; };
|
||||
34570A3A1B13222600E6D4FD /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
34570A3C1B13223000E6D4FD /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
|
||||
34570A3E1B13225500E6D4FD /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; };
|
||||
|
@ -1221,6 +1225,11 @@
|
|||
34F9FB8F1C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMStreetEditorEditTableViewCell.xib; sourceTree = "<group>"; };
|
||||
34FE4C431BCC013500066718 /* MWMMapWidgets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapWidgets.h; sourceTree = "<group>"; };
|
||||
34FE4C441BCC013500066718 /* MWMMapWidgets.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapWidgets.mm; sourceTree = "<group>"; };
|
||||
34FED54B1D1D45B900183B1B /* MWMLocationPredictor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMLocationPredictor.h; sourceTree = "<group>"; };
|
||||
34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMLocationPredictor.mm; sourceTree = "<group>"; };
|
||||
34FED54E1D21121000183B1B /* CLLocation+Mercator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CLLocation+Mercator.h"; sourceTree = "<group>"; };
|
||||
34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "CLLocation+Mercator.mm"; sourceTree = "<group>"; };
|
||||
34FED5521D2123CE00183B1B /* MWMLocationHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMLocationHelpers.h; sourceTree = "<group>"; };
|
||||
3D443C9C19E421EE0025C2FC /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
451950391B7A3E070085DA05 /* patterns.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = patterns.txt; path = ../../data/patterns.txt; sourceTree = "<group>"; };
|
||||
452FCA3A1B6A3DF7007019AB /* colors.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = colors.txt; path = ../../data/colors.txt; sourceTree = "<group>"; };
|
||||
|
@ -1347,8 +1356,6 @@
|
|||
A32B6D4A1A14980500E54A65 /* iosOGLContextFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iosOGLContextFactory.h; path = Platform/opengl/iosOGLContextFactory.h; sourceTree = "<group>"; };
|
||||
A32B6D4B1A14980500E54A65 /* iosOGLContextFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = iosOGLContextFactory.mm; path = Platform/opengl/iosOGLContextFactory.mm; sourceTree = "<group>"; };
|
||||
A367C93A1B17334800E2B6E7 /* resources-default */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-default"; path = "../../data/resources-default"; sourceTree = "<group>"; };
|
||||
A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LocationPredictor.mm; sourceTree = "<group>"; };
|
||||
A3CC2CD31A1C723900B832E1 /* LocationPredictor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocationPredictor.h; sourceTree = "<group>"; };
|
||||
B00511031A1101F600A61AA4 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||
B00511051A1101FC00A61AA4 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
|
||||
B08AA8D81A26299A00810B1C /* TimeUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeUtils.h; path = Categories/TimeUtils.h; sourceTree = "<group>"; };
|
||||
|
@ -1587,8 +1594,6 @@
|
|||
FA971562150920C600916690 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
FA99CB72147089B100689A9A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
FAA4B13E13EC1C8C00BCAB63 /* DiskFreeSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskFreeSpace.h; sourceTree = "<group>"; };
|
||||
FAA5C2A0144F135F005337F6 /* LocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocationManager.h; path = Platform/LocationManager.h; sourceTree = "<group>"; };
|
||||
FAA5C2A1144F135F005337F6 /* LocationManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = LocationManager.mm; path = Platform/LocationManager.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
FAA614B6155F16950031C345 /* AddSetVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AddSetVC.h; path = Bookmarks/AddSetVC.h; sourceTree = SOURCE_ROOT; };
|
||||
FAA614B7155F16950031C345 /* AddSetVC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AddSetVC.mm; path = Bookmarks/AddSetVC.mm; sourceTree = SOURCE_ROOT; };
|
||||
FAAEA7D0161BD26600CCD661 /* synonyms.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = synonyms.txt; path = ../../data/synonyms.txt; sourceTree = "<group>"; };
|
||||
|
@ -1738,6 +1743,7 @@
|
|||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
344D77B11D1BD79700DBED70 /* Location */,
|
||||
34479C741C60C6130065D261 /* Framework */,
|
||||
34CE8A641C7740CF00F4351A /* Storage */,
|
||||
34ABA61D1C2D514A00FE1BEC /* Input Validators */,
|
||||
|
@ -1766,8 +1772,6 @@
|
|||
348D1DF91C525B8300860465 /* MWMTypes.h */,
|
||||
F6DF5F321CD1136800A87154 /* LocaleTranslator.h */,
|
||||
F6381BF41CD12045004CA943 /* LocaleTranslator.mm */,
|
||||
A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */,
|
||||
A3CC2CD31A1C723900B832E1 /* LocationPredictor.h */,
|
||||
458287C21AD3BE2000BA8940 /* DownloadIndicatorProtocol.h */,
|
||||
F6F9BD221AD3C3A600308C33 /* Macros.h */,
|
||||
);
|
||||
|
@ -2033,6 +2037,18 @@
|
|||
path = Framework;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
344D77B11D1BD79700DBED70 /* Location */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34FED54B1D1D45B900183B1B /* MWMLocationPredictor.h */,
|
||||
34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */,
|
||||
344D77B21D1BD7C800DBED70 /* MWMLocationManager.h */,
|
||||
344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */,
|
||||
34FED5521D2123CE00183B1B /* MWMLocationHelpers.h */,
|
||||
);
|
||||
path = Location;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
345C34661CE9D32500BB2224 /* SideButtons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2567,6 +2583,8 @@
|
|||
34ABA61A1C2D4DCC00FE1BEC /* UITextField+RuntimeAttributes.mm */,
|
||||
F64DA8001C524BDE00330E9E /* UISwitch+RuntimeAttributes.h */,
|
||||
F64DA8011C524BDE00330E9E /* UISwitch+RuntimeAttributes.m */,
|
||||
34FED54E1D21121000183B1B /* CLLocation+Mercator.h */,
|
||||
34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */,
|
||||
);
|
||||
name = Categories;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3189,8 +3207,6 @@
|
|||
A32B6D491A14980500E54A65 /* iosOGLContext.mm */,
|
||||
A32B6D4A1A14980500E54A65 /* iosOGLContextFactory.h */,
|
||||
A32B6D4B1A14980500E54A65 /* iosOGLContextFactory.mm */,
|
||||
FAA5C2A0144F135F005337F6 /* LocationManager.h */,
|
||||
FAA5C2A1144F135F005337F6 /* LocationManager.mm */,
|
||||
);
|
||||
name = Platform;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3660,11 +3676,13 @@
|
|||
F6BC1E521ACBF98600EF0360 /* MWMFacebookAlert.mm in Sources */,
|
||||
F64F199D1AB81A00006EAF7E /* MWMDefaultAlert.mm in Sources */,
|
||||
F6E9BF321CE3658D0050E534 /* MWMBookmarkTitleCell.m in Sources */,
|
||||
344D77B41D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */,
|
||||
3438CDF81B8616760051AA78 /* MWMSearchShowOnMapCell.mm in Sources */,
|
||||
34F45E8E1B96E88100AC93F8 /* MWMSearchTabButtonsView.mm in Sources */,
|
||||
3490D2DE1CE9DD2500D0B838 /* MWMSideButtons.mm in Sources */,
|
||||
342FDDE51C6C9071000038A0 /* MWMMapDownloaderDataSource.mm in Sources */,
|
||||
347FD86B1C60B2CE002FB65E /* MWMOpeningHoursAddScheduleTableViewCell.mm in Sources */,
|
||||
34FED5501D21121000183B1B /* CLLocation+Mercator.mm in Sources */,
|
||||
34CD81BB1C91C24D007D2A60 /* MWMWelcomeController.mm in Sources */,
|
||||
F6C934401AE64E4200DDC624 /* MWMSpringAnimation.mm in Sources */,
|
||||
34B82ACA1B8465C100180497 /* MWMSearchCategoryCell.mm in Sources */,
|
||||
|
@ -3683,7 +3701,6 @@
|
|||
34CCFDD11C21945500F28959 /* MWMPlacePageOpeningHoursDayView.mm in Sources */,
|
||||
F61579341AC2CE9A0032D8E9 /* MWMRateAlert.mm in Sources */,
|
||||
F6BB6CC61BB18C0900DF1DF2 /* MWMRoutePointCell.m in Sources */,
|
||||
A3CC2CD41A1C723900B832E1 /* LocationPredictor.mm in Sources */,
|
||||
347D7C691C2C0703006B2D0A /* UITextView+RuntimeAttributes.mm in Sources */,
|
||||
34181EB91C0ED1C30081B586 /* MWMOpeningHoursSection.mm in Sources */,
|
||||
F6D4A72F1CC1030E00BD4E5B /* MWMEditorNotesFooter.mm in Sources */,
|
||||
|
@ -3758,7 +3775,6 @@
|
|||
347FD8851C60B2CE002FB65E /* MWMOpeningHoursTimeSelectorTableViewCell.mm in Sources */,
|
||||
34EB84581C073DF70004689F /* MWMOpeningHoursEditorViewController.mm in Sources */,
|
||||
349A357A1B53D4C9009677EE /* MWMCircularProgress.mm in Sources */,
|
||||
FAA5C2A2144F135F005337F6 /* LocationManager.mm in Sources */,
|
||||
34B82ADA1B847FFC00180497 /* MWMSearchCell.mm in Sources */,
|
||||
F6FEA82D1C58E89B007223CC /* MWMButton.mm in Sources */,
|
||||
F66A8FAC1B09F137001B9C97 /* MWMiPadPlacePage.mm in Sources */,
|
||||
|
@ -3823,6 +3839,7 @@
|
|||
34B82AE21B84AC5E00180497 /* MWMSearchCategoriesManager.mm in Sources */,
|
||||
34CE8A671C7740E100F4351A /* MWMStorage.mm in Sources */,
|
||||
F6F533A31B3C248900C1940B /* UIColor+MapsMeColor.mm in Sources */,
|
||||
34FED54D1D1D45B900183B1B /* MWMLocationPredictor.mm in Sources */,
|
||||
346EDADB1B9F0E35004F8DB5 /* MWMMultilineLabel.mm in Sources */,
|
||||
34C9BD041C6DB693000DC38D /* MWMViewController.mm in Sources */,
|
||||
CB252D6F16FF82C9001E41E9 /* Statistics.mm in Sources */,
|
||||
|
@ -3877,6 +3894,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6741A9A21BF340DE002C974C /* CommunityVC.mm in Sources */,
|
||||
34FED5511D21121000183B1B /* CLLocation+Mercator.mm in Sources */,
|
||||
6741A9A31BF340DE002C974C /* main.mm in Sources */,
|
||||
6741A9A41BF340DE002C974C /* MWMSearchTabbedViewController.mm in Sources */,
|
||||
6741A9A51BF340DE002C974C /* MWMShareLocationActivityItem.mm in Sources */,
|
||||
|
@ -3886,6 +3904,7 @@
|
|||
6741A9A81BF340DE002C974C /* MWMFacebookAlert.mm in Sources */,
|
||||
6741A9A91BF340DE002C974C /* MWMDefaultAlert.mm in Sources */,
|
||||
F6E9BF331CE3658D0050E534 /* MWMBookmarkTitleCell.m in Sources */,
|
||||
344D77B51D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */,
|
||||
6741A9AA1BF340DE002C974C /* MWMSearchShowOnMapCell.mm in Sources */,
|
||||
6741A9AC1BF340DE002C974C /* MWMSearchTabButtonsView.mm in Sources */,
|
||||
3490D2DF1CE9DD2500D0B838 /* MWMSideButtons.mm in Sources */,
|
||||
|
@ -3907,7 +3926,6 @@
|
|||
34CCFDD21C21945500F28959 /* MWMPlacePageOpeningHoursDayView.mm in Sources */,
|
||||
6741A9B91BF340DE002C974C /* MWMRateAlert.mm in Sources */,
|
||||
6741A9BA1BF340DE002C974C /* MWMRoutePointCell.m in Sources */,
|
||||
6741A9BB1BF340DE002C974C /* LocationPredictor.mm in Sources */,
|
||||
347D7C6A1C2C0703006B2D0A /* UITextView+RuntimeAttributes.mm in Sources */,
|
||||
6741A9BE1BF340DE002C974C /* UILabel+RuntimeAttributes.mm in Sources */,
|
||||
6741A9BF1BF340DE002C974C /* MWMSearchTabbedCollectionViewCell.mm in Sources */,
|
||||
|
@ -3948,6 +3966,7 @@
|
|||
6741A9D41BF340DE002C974C /* MWMAlertViewController.mm in Sources */,
|
||||
F6FE3C391CC50FFD00A73196 /* MWMPlaceDoesntExistAlert.mm in Sources */,
|
||||
34C9BD0A1C6DBCDA000DC38D /* MWMNavigationController.mm in Sources */,
|
||||
34D866DE1D213E8B00B593F8 /* MWMLocationPredictor.mm in Sources */,
|
||||
3406FA161C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm in Sources */,
|
||||
6741A9D51BF340DE002C974C /* WebViewController.mm in Sources */,
|
||||
34C9BD031C6DB693000DC38D /* MWMTableViewController.mm in Sources */,
|
||||
|
@ -3981,7 +4000,6 @@
|
|||
6741A9EB1BF340DE002C974C /* ContextViews.mm in Sources */,
|
||||
6741A9EC1BF340DE002C974C /* MWMCircularProgress.mm in Sources */,
|
||||
342CC5F21C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.mm in Sources */,
|
||||
6741A9ED1BF340DE002C974C /* LocationManager.mm in Sources */,
|
||||
6741A9EE1BF340DE002C974C /* MWMSearchCell.mm in Sources */,
|
||||
6741A9EF1BF340DE002C974C /* MWMiPadPlacePage.mm in Sources */,
|
||||
6741A9F01BF340DE002C974C /* SettingsViewController.mm in Sources */,
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <UIKit/UIApplication.h>
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
#include "platform/location.hpp"
|
||||
#include "std/utility.hpp"
|
||||
|
||||
@protocol LocationObserver
|
||||
@required
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info;
|
||||
@optional
|
||||
- (void)onLocationError:(location::TLocationError)errorCode;
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info;
|
||||
@end
|
||||
|
||||
@interface LocationManager : NSObject <CLLocationManagerDelegate>
|
||||
|
||||
@property (nonatomic, readonly) BOOL isStarted;
|
||||
@property (nonatomic, readonly) location::TLocationError lastLocationError;
|
||||
|
||||
- (void)start:(id <LocationObserver>)observer;
|
||||
- (void)stop:(id <LocationObserver>)observer;
|
||||
- (CLLocation *)lastLocation;
|
||||
- (CLHeading *)lastHeading;
|
||||
// Fixes compass angle orientation when rotating screen to landscape
|
||||
- (void)orientationChanged;
|
||||
|
||||
- (bool)getLat:(double &)lat Lon:(double &)lon;
|
||||
- (bool)getNorthRad:(double &)rad;
|
||||
|
||||
+ (NSString *)formattedDistance:(double)meters;
|
||||
// Returns nil if neither speed nor altitude are available
|
||||
- (NSString *)formattedSpeedAndAltitude:(BOOL &)hasSpeed;
|
||||
|
||||
- (bool)lastLocationIsValid;
|
||||
- (bool)isLocationPendingOrNoPosition;
|
||||
- (BOOL)enabledOnMap;
|
||||
|
||||
- (void)onDaemonMode;
|
||||
- (void)onForeground;
|
||||
- (void)onBackground;
|
||||
- (void)beforeTerminate;
|
||||
|
||||
- (void)reset;
|
||||
|
||||
- (void)processMyPositionStateModeEvent:(location::EMyPositionMode)mode;
|
||||
|
||||
@end
|
||||
|
||||
@interface CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator;
|
||||
|
||||
@end
|
||||
|
||||
static inline ms::LatLon ToLatLon(m2::PointD const & p)
|
||||
{
|
||||
return MercatorBounds::ToLatLon(p);
|
||||
}
|
||||
|
||||
static inline m2::PointD ToMercator(CLLocationCoordinate2D const & l)
|
||||
{
|
||||
return MercatorBounds::FromLatLon(l.latitude, l.longitude);
|
||||
}
|
||||
|
||||
static inline m2::PointD ToMercator(ms::LatLon const & l)
|
||||
{
|
||||
return MercatorBounds::FromLatLon(l);
|
||||
}
|
|
@ -1,549 +0,0 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "Statistics.h"
|
||||
|
||||
#import "3party/Alohalytics/src/alohalytics_objc.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
#include "map/gps_tracker.hpp"
|
||||
#include "routing/router.hpp"
|
||||
#include "platform/file_logging.hpp"
|
||||
#include "platform/measurement_utils.hpp"
|
||||
#include "platform/settings.hpp"
|
||||
|
||||
#include "base/math.hpp"
|
||||
|
||||
static CLAuthorizationStatus const kRequestAuthStatus = kCLAuthorizationStatusAuthorizedAlways;
|
||||
static NSString * const kAlohalyticsLocationRequestAlwaysFailed = @"$locationAlwaysRequestErrorDenied";
|
||||
|
||||
namespace
|
||||
{
|
||||
enum class GeoMode
|
||||
{
|
||||
Pending,
|
||||
InPosition,
|
||||
NotInPosition,
|
||||
FollowAndRotate,
|
||||
VehicleRouting,
|
||||
PedestrianRouting,
|
||||
BicycleRouting
|
||||
};
|
||||
|
||||
struct DesiredAccuracy
|
||||
{
|
||||
CLLocationAccuracy charging;
|
||||
CLLocationAccuracy battery;
|
||||
};
|
||||
|
||||
struct GeoModeSettings
|
||||
{
|
||||
CLLocationDistance distanceFilter;
|
||||
DesiredAccuracy accuracy;
|
||||
};
|
||||
|
||||
map<GeoMode, GeoModeSettings> const kGeoSettings{
|
||||
{GeoMode::Pending,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBestForNavigation}}},
|
||||
{GeoMode::InPosition,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::NotInPosition,
|
||||
{.distanceFilter = 5,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::FollowAndRotate,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::VehicleRouting,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::PedestrianRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::BicycleRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}}};
|
||||
} // namespace
|
||||
|
||||
@interface LocationManager ()
|
||||
|
||||
@property (nonatomic) BOOL deferringUpdates;
|
||||
|
||||
@property (nonatomic) CLLocationManager * locationManager;
|
||||
|
||||
@property (nonatomic, readwrite) BOOL isStarted;
|
||||
@property (nonatomic, readwrite) location::TLocationError lastLocationError;
|
||||
@property (nonatomic) NSMutableSet * observers;
|
||||
@property (nonatomic) NSDate * lastLocationTime;
|
||||
|
||||
@property (nonatomic) GeoMode geoMode;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LocationManager
|
||||
|
||||
- (void)batteryStateChangedNotification:(NSNotification *)notification
|
||||
{
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
- (void)refreshGeoModeSettings
|
||||
{
|
||||
UIDeviceBatteryState const state = [UIDevice currentDevice].batteryState;
|
||||
BOOL const isCharging = (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull);
|
||||
GeoModeSettings const settings = kGeoSettings.at(self.geoMode);
|
||||
self.locationManager.desiredAccuracy = isCharging ? settings.accuracy.charging : settings.accuracy.battery;
|
||||
self.locationManager.distanceFilter = settings.distanceFilter;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
- (void)onDaemonMode
|
||||
{
|
||||
[self.locationManager stopMonitoringSignificantLocationChanges];
|
||||
LOG(LINFO, ("startUpdatingLocation"));
|
||||
[self.locationManager startUpdatingLocation];
|
||||
}
|
||||
|
||||
- (void)onBackground
|
||||
{
|
||||
if (!GpsTracker::Instance().IsEnabled())
|
||||
{
|
||||
LOG(LINFO, ("stopUpdatingLocation"));
|
||||
[self.locationManager stopUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beforeTerminate
|
||||
{
|
||||
if (!GpsTracker::Instance().IsEnabled())
|
||||
return;
|
||||
[self.locationManager startMonitoringSignificantLocationChanges];
|
||||
}
|
||||
|
||||
- (void)onForeground
|
||||
{
|
||||
[self onDaemonMode];
|
||||
[self.locationManager disallowDeferredLocationUpdates];
|
||||
self.deferringUpdates = NO;
|
||||
[self orientationChanged];
|
||||
}
|
||||
|
||||
- (void)start:(id <LocationObserver>)observer
|
||||
{
|
||||
if (!self.isStarted)
|
||||
{
|
||||
//YES if location services are enabled; NO if they are not.
|
||||
if ([CLLocationManager locationServicesEnabled])
|
||||
{
|
||||
CLAuthorizationStatus const authStatus = [CLLocationManager authorizationStatus];
|
||||
switch (authStatus)
|
||||
{
|
||||
case kCLAuthorizationStatusAuthorizedWhenInUse:
|
||||
case kCLAuthorizationStatusAuthorizedAlways:
|
||||
case kCLAuthorizationStatusNotDetermined:
|
||||
if (kRequestAuthStatus == kCLAuthorizationStatusAuthorizedAlways && [self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
|
||||
[self.locationManager requestAlwaysAuthorization];
|
||||
LOG(LINFO, ("startUpdatingLocation"));
|
||||
[self.locationManager startUpdatingLocation];
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[self.locationManager startUpdatingHeading];
|
||||
self.isStarted = YES;
|
||||
[self.observers addObject:observer];
|
||||
break;
|
||||
case kCLAuthorizationStatusRestricted:
|
||||
case kCLAuthorizationStatusDenied:
|
||||
[self observer:observer onLocationError:location::EDenied];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
[self observer:observer onLocationError:location::EGPSIsOff];
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL updateLocation = ![self.observers containsObject:observer];
|
||||
[self.observers addObject:observer];
|
||||
if ([self lastLocationIsValid] && updateLocation)
|
||||
{
|
||||
// pass last location known location when new observer is attached
|
||||
// (default CLLocationManagerDelegate behaviour)
|
||||
[observer onLocationUpdate:gpsInfoFromLocation(self.lastLocation)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stop:(id <LocationObserver>)observer
|
||||
{
|
||||
[self.observers removeObject:observer];
|
||||
if (self.isStarted && self.observers.count == 0)
|
||||
{
|
||||
// stop only if no more observers are subsribed
|
||||
self.isStarted = NO;
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[self.locationManager stopUpdatingHeading];
|
||||
LOG(LINFO, ("stopUpdatingLocation"));
|
||||
[self.locationManager stopUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
- (CLLocation *)lastLocation
|
||||
{
|
||||
if (!self.isStarted || self.locationManager.location.horizontalAccuracy < 0.)
|
||||
return nil;
|
||||
return self.locationManager.location;
|
||||
}
|
||||
|
||||
- (CLHeading *)lastHeading
|
||||
{
|
||||
if (!self.isStarted || self.locationManager.heading.headingAccuracy < 0.)
|
||||
return nil;
|
||||
return self.locationManager.heading;
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading
|
||||
{
|
||||
[self notifyCompassUpdate:compasInfoFromHeading(heading)];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
|
||||
{
|
||||
[self processLocation:locations.lastObject];
|
||||
if (!self.deferringUpdates)
|
||||
return;
|
||||
[self.locationManager allowDeferredLocationUpdatesUntilTraveled:300 timeout:15];
|
||||
self.deferringUpdates = NO;
|
||||
}
|
||||
|
||||
- (BOOL)deferringUpdates
|
||||
{
|
||||
return _deferringUpdates && [CLLocationManager deferredLocationUpdatesAvailable] &&
|
||||
[UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
|
||||
}
|
||||
|
||||
- (void)processLocation:(CLLocation *)location
|
||||
{
|
||||
// According to documentation, lat and lon are valid only if horz acc is non-negative.
|
||||
// So we filter out such events completely.
|
||||
if (location.horizontalAccuracy < 0.)
|
||||
return;
|
||||
|
||||
self.lastLocationError = location::TLocationError::ENoError;
|
||||
// Save current device time for location.
|
||||
self.lastLocationTime = [NSDate date];
|
||||
[[Statistics instance] logLocation:location];
|
||||
auto const newInfo = gpsInfoFromLocation(location);
|
||||
if (!MapsAppDelegate.theApp.isDaemonMode)
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
[observer onLocationUpdate:newInfo];
|
||||
// TODO(AlexZ): Temporary, remove in the future.
|
||||
}
|
||||
GpsTracker::Instance().OnLocationUpdated(newInfo);
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error
|
||||
{
|
||||
self.deferringUpdates = YES;
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
NSLog(@"locationManager failed with error: %ld, %@", (long)error.code, error.description);
|
||||
if (error.code == kCLErrorDenied)
|
||||
{
|
||||
if (kRequestAuthStatus == kCLAuthorizationStatusAuthorizedAlways && [self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
|
||||
[Alohalytics logEvent:kAlohalyticsLocationRequestAlwaysFailed];
|
||||
for (id observer in self.observers.copy)
|
||||
[self observer:observer onLocationError:location::EDenied];
|
||||
}
|
||||
else if (error.code != kCLErrorLocationUnknown)
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
[self observer:observer onLocationError:location::ENotSupported];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
|
||||
{
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return NO;
|
||||
bool on = false;
|
||||
settings::Get("CompassCalibrationEnabled", on);
|
||||
if (!on)
|
||||
return NO;
|
||||
|
||||
if (!MapsAppDelegate.theApp.mapViewController.controlsManager.searchHidden)
|
||||
return NO;
|
||||
if (!manager.heading)
|
||||
return YES;
|
||||
else if (manager.heading.headingAccuracy < 0)
|
||||
return YES;
|
||||
else if (manager.heading.headingAccuracy > 5)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (bool)getLat:(double &)lat Lon:(double &)lon
|
||||
{
|
||||
CLLocation * l = [self lastLocation];
|
||||
|
||||
// Return last saved location if it's not later than 5 minutes.
|
||||
if ([self lastLocationIsValid])
|
||||
{
|
||||
lat = l.coordinate.latitude;
|
||||
lon = l.coordinate.longitude;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
- (bool)getNorthRad:(double &)rad
|
||||
{
|
||||
CLHeading * h = [self lastHeading];
|
||||
|
||||
if (h != nil)
|
||||
{
|
||||
rad = (h.trueHeading < 0) ? h.magneticHeading : h.trueHeading;
|
||||
rad = my::DegToRad(rad);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+ (NSString *)formattedDistance:(double)meters
|
||||
{
|
||||
if (meters < 0.)
|
||||
return nil;
|
||||
|
||||
string s;
|
||||
MeasurementUtils::FormatDistance(meters, s);
|
||||
return @(s.c_str());
|
||||
}
|
||||
|
||||
+ (char const *)getSpeedSymbol:(double)metersPerSecond
|
||||
{
|
||||
// 0-1 m/s
|
||||
static char const * turtle = "\xF0\x9F\x90\xA2 ";
|
||||
// 1-2 m/s
|
||||
static char const * pedestrian = "\xF0\x9F\x9A\xB6 ";
|
||||
// 2-5 m/s
|
||||
static char const * tractor = "\xF0\x9F\x9A\x9C ";
|
||||
// 5-10 m/s
|
||||
static char const * bicycle = "\xF0\x9F\x9A\xB2 ";
|
||||
// 10-36 m/s
|
||||
static char const * car = "\xF0\x9F\x9A\x97 ";
|
||||
// 36-120 m/s
|
||||
static char const * train = "\xF0\x9F\x9A\x85 ";
|
||||
// 120-278 m/s
|
||||
static char const * airplane = "\xE2\x9C\x88\xEF\xB8\x8F ";
|
||||
// 278+
|
||||
static char const * rocket = "\xF0\x9F\x9A\x80 ";
|
||||
|
||||
if (metersPerSecond <= 1.) return turtle;
|
||||
else if (metersPerSecond <= 2.) return pedestrian;
|
||||
else if (metersPerSecond <= 5.) return tractor;
|
||||
else if (metersPerSecond <= 10.) return bicycle;
|
||||
else if (metersPerSecond <= 36.) return car;
|
||||
else if (metersPerSecond <= 120.) return train;
|
||||
else if (metersPerSecond <= 278.) return airplane;
|
||||
else return rocket;
|
||||
}
|
||||
|
||||
- (NSString *)formattedSpeedAndAltitude:(BOOL &)hasSpeed
|
||||
{
|
||||
hasSpeed = NO;
|
||||
CLLocation * l = [self lastLocation];
|
||||
if (l)
|
||||
{
|
||||
string result;
|
||||
if (l.altitude)
|
||||
result = "\xE2\x96\xB2 " /* this is simple mountain symbol */ + MeasurementUtils::FormatAltitude(l.altitude);
|
||||
// Speed is actual only for just received location
|
||||
if (l.speed > 0. && [l.timestamp timeIntervalSinceNow] >= -2.0)
|
||||
{
|
||||
hasSpeed = YES;
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += [LocationManager getSpeedSymbol:l.speed] + MeasurementUtils::FormatSpeed(l.speed);
|
||||
}
|
||||
return result.empty() ? nil : @(result.c_str());
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (bool)lastLocationIsValid
|
||||
{
|
||||
return (([self lastLocation] != nil) && ([self.lastLocationTime timeIntervalSinceNow] > -300.0));
|
||||
}
|
||||
|
||||
- (bool)isLocationPendingOrNoPosition
|
||||
{
|
||||
using location::EMyPositionMode;
|
||||
EMyPositionMode mode;
|
||||
if (!settings::Get(settings::kLocationStateMode, mode))
|
||||
return true;
|
||||
return mode == EMyPositionMode::PendingPosition || mode == EMyPositionMode::NotFollowNoPosition;
|
||||
}
|
||||
|
||||
- (BOOL)enabledOnMap
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
if ([observer isKindOfClass:[MapViewController class]])
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)orientationChanged
|
||||
{
|
||||
self.locationManager.headingOrientation = (CLDeviceOrientation)[UIDevice currentDevice].orientation;
|
||||
}
|
||||
|
||||
- (void)notifyCompassUpdate:(location::CompassInfo const &)newInfo
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
if ([observer respondsToSelector:@selector(onCompassUpdate:)])
|
||||
[observer onCompassUpdate:newInfo];
|
||||
}
|
||||
|
||||
- (void)observer:(id<LocationObserver>)observer onLocationError:(location::TLocationError)errorCode
|
||||
{
|
||||
self.lastLocationError = errorCode;
|
||||
if ([(NSObject *)observer respondsToSelector:@selector(onLocationError:)])
|
||||
[observer onLocationError:errorCode];
|
||||
}
|
||||
|
||||
location::GpsInfo gpsInfoFromLocation(CLLocation const * l)
|
||||
{
|
||||
location::GpsInfo info;
|
||||
info.m_source = location::EAppleNative;
|
||||
|
||||
info.m_latitude = l.coordinate.latitude;
|
||||
info.m_longitude = l.coordinate.longitude;
|
||||
info.m_timestamp = [l.timestamp timeIntervalSince1970];
|
||||
|
||||
if (l.horizontalAccuracy >= 0.0)
|
||||
info.m_horizontalAccuracy = l.horizontalAccuracy;
|
||||
|
||||
if (l.verticalAccuracy >= 0.0)
|
||||
{
|
||||
info.m_verticalAccuracy = l.verticalAccuracy;
|
||||
info.m_altitude = l.altitude;
|
||||
}
|
||||
|
||||
if (l.course >= 0.0)
|
||||
info.m_bearing = l.course;
|
||||
|
||||
if (l.speed >= 0.0)
|
||||
info.m_speed = l.speed;
|
||||
return info;
|
||||
}
|
||||
|
||||
location::CompassInfo compasInfoFromHeading(CLHeading const * h)
|
||||
{
|
||||
location::CompassInfo info;
|
||||
if (h.trueHeading >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.trueHeading);
|
||||
else if (h.headingAccuracy >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.magneticHeading);
|
||||
return info;
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
_isStarted = NO;
|
||||
_lastLocationTime = nil;
|
||||
_observers = [NSMutableSet set];
|
||||
_locationManager.delegate = nil;
|
||||
_locationManager = nil;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)processMyPositionStateModeEvent:(location::EMyPositionMode)mode
|
||||
{
|
||||
auto const & f = GetFramework();
|
||||
if (f.IsRoutingActive())
|
||||
{
|
||||
switch (f.GetRouter())
|
||||
{
|
||||
case routing::RouterType::Vehicle:
|
||||
self.geoMode = GeoMode::VehicleRouting;
|
||||
break;
|
||||
case routing::RouterType::Pedestrian:
|
||||
self.geoMode = GeoMode::PedestrianRouting;
|
||||
break;
|
||||
case routing::RouterType::Bicycle:
|
||||
self.geoMode = GeoMode::BicycleRouting;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case location::EMyPositionMode::PendingPosition:
|
||||
self.geoMode = GeoMode::Pending;
|
||||
break;
|
||||
case location::EMyPositionMode::NotFollowNoPosition:
|
||||
case location::EMyPositionMode::NotFollow:
|
||||
self.geoMode = GeoMode::NotInPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::Follow:
|
||||
self.geoMode = GeoMode::InPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::FollowAndRotate:
|
||||
self.geoMode = GeoMode::FollowAndRotate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (CLLocationManager *)locationManager
|
||||
{
|
||||
if (!_locationManager)
|
||||
{
|
||||
[self reset];
|
||||
_locationManager = [[CLLocationManager alloc] init];
|
||||
_locationManager.delegate = self;
|
||||
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
|
||||
[self refreshGeoModeSettings];
|
||||
if (!(isIOS7 || isIOS8))
|
||||
_locationManager.allowsBackgroundLocationUpdates = YES;
|
||||
_locationManager.pausesLocationUpdatesAutomatically = YES;
|
||||
_locationManager.headingFilter = 3.0;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryStateChangedNotification:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
|
||||
}
|
||||
return _locationManager;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator
|
||||
{
|
||||
return ToMercator(self.coordinate);
|
||||
}
|
||||
|
||||
@end
|
Loading…
Add table
Reference in a new issue