diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/system/mac/CoreLocationLocationProvider.mm | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/system/mac/CoreLocationLocationProvider.mm')
-rw-r--r-- | dom/system/mac/CoreLocationLocationProvider.mm | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/dom/system/mac/CoreLocationLocationProvider.mm b/dom/system/mac/CoreLocationLocationProvider.mm new file mode 100644 index 000000000..b39582a9e --- /dev/null +++ b/dom/system/mac/CoreLocationLocationProvider.mm @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsAutoPtr.h" +#include "nsCOMPtr.h" +#include "nsGeoPosition.h" +#include "nsIConsoleService.h" +#include "nsServiceManagerUtils.h" +#include "nsIDOMGeoPositionError.h" +#include "CoreLocationLocationProvider.h" +#include "nsCocoaFeatures.h" +#include "prtime.h" +#include "mozilla/Telemetry.h" +#include "MLSFallback.h" + +#include <CoreLocation/CLError.h> +#include <CoreLocation/CLLocation.h> +#include <CoreLocation/CLLocationManager.h> +#include <CoreLocation/CLLocationManagerDelegate.h> + +#include <objc/objc.h> +#include <objc/objc-runtime.h> + +#include "nsObjCExceptions.h" + +using namespace mozilla; + +static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest; +static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTenMeters; + +@interface LocationDelegate : NSObject <CLLocationManagerDelegate> +{ + CoreLocationLocationProvider* mProvider; +} + +- (id)init:(CoreLocationLocationProvider*)aProvider; +- (void)locationManager:(CLLocationManager*)aManager + didFailWithError:(NSError *)aError; +- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)locations; + +@end + +@implementation LocationDelegate +- (id) init:(CoreLocationLocationProvider*) aProvider +{ + if ((self = [super init])) { + mProvider = aProvider; + } + + return self; +} + +- (void)locationManager:(CLLocationManager*)aManager + didFailWithError:(NSError *)aError +{ + nsCOMPtr<nsIConsoleService> console = + do_GetService(NS_CONSOLESERVICE_CONTRACTID); + + NS_ENSURE_TRUE_VOID(console); + + NSString* message = + [@"Failed to acquire position: " stringByAppendingString: [aError localizedDescription]]; + + console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get()); + + if ([aError code] == kCLErrorDenied) { + mProvider->NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED); + return; + } + + // The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this. + // The concept here is: on error, hand off geolocation to MLS, which will then report + // back a location or error. We can't call this with no delay however, as this method + // is called with an error code of 0 in both failed geolocation cases, and also when + // geolocation is not immediately available. + // The 2 sec delay is arbitrarily large enough that CL has a reasonable head start and + // if it is likely to succeed, it should complete before the MLS provider. + // Take note that in locationManager:didUpdateLocations: the handoff to MLS is stopped. + mProvider->CreateMLSFallbackProvider(); +} + +- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)aLocations +{ + if (aLocations.count < 1) { + return; + } + + mProvider->CancelMLSFallbackProvider(); + + CLLocation* location = [aLocations objectAtIndex:0]; + + nsCOMPtr<nsIDOMGeoPosition> geoPosition = + new nsGeoPosition(location.coordinate.latitude, + location.coordinate.longitude, + location.altitude, + location.horizontalAccuracy, + location.verticalAccuracy, + location.course, + location.speed, + PR_Now() / PR_USEC_PER_MSEC); + + mProvider->Update(geoPosition); + Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, false); +} +@end + +NS_IMPL_ISUPPORTS(CoreLocationLocationProvider::MLSUpdate, nsIGeolocationUpdate); + +CoreLocationLocationProvider::MLSUpdate::MLSUpdate(CoreLocationLocationProvider& parentProvider) + : mParentLocationProvider(parentProvider) +{ +} + +CoreLocationLocationProvider::MLSUpdate::~MLSUpdate() +{ +} + +NS_IMETHODIMP +CoreLocationLocationProvider::MLSUpdate::Update(nsIDOMGeoPosition *position) +{ + nsCOMPtr<nsIDOMGeoPositionCoords> coords; + position->GetCoords(getter_AddRefs(coords)); + if (!coords) { + return NS_ERROR_FAILURE; + } + mParentLocationProvider.Update(position); + Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, true); + return NS_OK; +} +NS_IMETHODIMP +CoreLocationLocationProvider::MLSUpdate::NotifyError(uint16_t error) +{ + mParentLocationProvider.NotifyError(error); + return NS_OK; +} +class CoreLocationObjects { +public: + nsresult Init(CoreLocationLocationProvider* aProvider) { + mLocationManager = [[CLLocationManager alloc] init]; + NS_ENSURE_TRUE(mLocationManager, NS_ERROR_NOT_AVAILABLE); + + mLocationDelegate = [[LocationDelegate alloc] init:aProvider]; + NS_ENSURE_TRUE(mLocationDelegate, NS_ERROR_NOT_AVAILABLE); + + mLocationManager.desiredAccuracy = kDEFAULT_ACCURACY; + mLocationManager.delegate = mLocationDelegate; + + return NS_OK; + } + + ~CoreLocationObjects() { + if (mLocationManager) { + [mLocationManager release]; + } + + if (mLocationDelegate) { + [mLocationDelegate release]; + } + } + + LocationDelegate* mLocationDelegate; + CLLocationManager* mLocationManager; +}; + +NS_IMPL_ISUPPORTS(CoreLocationLocationProvider, nsIGeolocationProvider) + +CoreLocationLocationProvider::CoreLocationLocationProvider() + : mCLObjects(nullptr), mMLSFallbackProvider(nullptr) +{ +} + +CoreLocationLocationProvider::~CoreLocationLocationProvider() +{ +} + +NS_IMETHODIMP +CoreLocationLocationProvider::Startup() +{ + if (!mCLObjects) { + nsAutoPtr<CoreLocationObjects> clObjs(new CoreLocationObjects()); + + nsresult rv = clObjs->Init(this); + NS_ENSURE_SUCCESS(rv, rv); + + mCLObjects = clObjs.forget(); + } + + // Must be stopped before starting or response (success or failure) is not guaranteed + [mCLObjects->mLocationManager stopUpdatingLocation]; + [mCLObjects->mLocationManager startUpdatingLocation]; + return NS_OK; +} + +NS_IMETHODIMP +CoreLocationLocationProvider::Watch(nsIGeolocationUpdate* aCallback) +{ + if (mCallback) { + return NS_OK; + } + + mCallback = aCallback; + return NS_OK; +} + +NS_IMETHODIMP +CoreLocationLocationProvider::Shutdown() +{ + NS_ENSURE_STATE(mCLObjects); + + [mCLObjects->mLocationManager stopUpdatingLocation]; + + delete mCLObjects; + mCLObjects = nullptr; + + if (mMLSFallbackProvider) { + mMLSFallbackProvider->Shutdown(); + mMLSFallbackProvider = nullptr; + } + + return NS_OK; +} + +NS_IMETHODIMP +CoreLocationLocationProvider::SetHighAccuracy(bool aEnable) +{ + NS_ENSURE_STATE(mCLObjects); + + mCLObjects->mLocationManager.desiredAccuracy = + (aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY); + + return NS_OK; +} + +void +CoreLocationLocationProvider::Update(nsIDOMGeoPosition* aSomewhere) +{ + if (aSomewhere && mCallback) { + mCallback->Update(aSomewhere); + } +} + +void +CoreLocationLocationProvider::NotifyError(uint16_t aErrorCode) +{ + mCallback->NotifyError(aErrorCode); +} + +void +CoreLocationLocationProvider::CreateMLSFallbackProvider() +{ + if (mMLSFallbackProvider) { + return; + } + + mMLSFallbackProvider = new MLSFallback(); + mMLSFallbackProvider->Startup(new MLSUpdate(*this)); +} + +void +CoreLocationLocationProvider::CancelMLSFallbackProvider() +{ + if (!mMLSFallbackProvider) { + return; + } + + mMLSFallbackProvider->Shutdown(); + mMLSFallbackProvider = nullptr; +} |