diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp index ff76e233b4c9..9499ee0dc234 100644 --- a/dom/geolocation/Geolocation.cpp +++ b/dom/geolocation/Geolocation.cpp @@ -347,8 +347,8 @@ void Geolocation::ReallowWithSystemPermissionOrCancel( denyPermissionOnError.release(); RefPtr permissionRequest = - geolocation::PresentSystemSettings(aBrowsingContext, - std::move(aResolver)); + geolocation::RequestLocationPermissionFromUser(aBrowsingContext, + std::move(aResolver)); NS_ENSURE_TRUE_VOID(permissionRequest); auto cancelRequestOnError = MakeScopeExit([&]() { @@ -387,12 +387,13 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { return NS_OK; } - if (mBehavior == SystemGeolocationPermissionBehavior::GeckoWillPromptUser) { - // Asynchronously present the system dialog and wait for the permission to - // change or the request to be canceled. If the permission is (maybe) - // granted then it will call Allow again. It actually will also re-call - // Allow if the permission is denied, in order to get the "denied - // permission" behavior. + if (mBehavior != SystemGeolocationPermissionBehavior::NoPrompt) { + // Asynchronously present the system dialog or open system preferences + // (RequestGeolocationPermissionFromUser will know which to do), and wait + // for the permission to change or the request to be canceled. If the + // permission is (maybe) granted then it will call Allow again. It actually + // will also re-call Allow if the permission is denied, in order to get the + // "denied permission" behavior. mBehavior = SystemGeolocationPermissionBehavior::NoPrompt; RefPtr browsingContext = mWindow->GetBrowsingContext(); if (ContentChild* cc = ContentChild::GetSingleton()) { diff --git a/dom/geolocation/GeolocationSystem.cpp b/dom/geolocation/GeolocationSystem.cpp index be9f20d685f9..9ef44019bce5 100644 --- a/dom/geolocation/GeolocationSystem.cpp +++ b/dom/geolocation/GeolocationSystem.cpp @@ -12,8 +12,9 @@ SystemGeolocationPermissionBehavior GetGeolocationPermissionBehavior() { return SystemGeolocationPermissionBehavior::NoPrompt; } -already_AddRefed PresentSystemSettings( - BrowsingContext* aBrowsingContext, ParentRequestResolver&& aResolver) { +already_AddRefed +RequestLocationPermissionFromUser(BrowsingContext* aBrowsingContext, + ParentRequestResolver&& aResolver) { MOZ_ASSERT_UNREACHABLE( "Should not warn user of need for system location permission " "since we cannot open system settings on this platform."); diff --git a/dom/geolocation/GeolocationSystem.h b/dom/geolocation/GeolocationSystem.h index 36c26a00124f..b093f34601c2 100644 --- a/dom/geolocation/GeolocationSystem.h +++ b/dom/geolocation/GeolocationSystem.h @@ -41,12 +41,13 @@ using ParentRequestResolver = PContentParent::RequestGeolocationPermissionFromUserResolver; /** - * Opens the relevant (system or Gecko) window to request permission from the - * user. Resolves aResolver when permission is granted, an error occurs, or Stop - * has been called on the SystemGeolocationPermissionRequest. + * Opens the relevant system dialog to request permission from the user. + * Resolves aResolver when permission is granted, an error occurs, or Stop has + * been called on the SystemGeolocationPermissionRequest. */ -already_AddRefed PresentSystemSettings( - BrowsingContext* aBrowsingContext, ParentRequestResolver&& aResolver); +already_AddRefed +RequestLocationPermissionFromUser(BrowsingContext* aBrowsingContext, + ParentRequestResolver&& aResolver); } // namespace geolocation } // namespace mozilla::dom diff --git a/dom/geolocation/GeolocationSystemWin.cpp b/dom/geolocation/GeolocationSystemWin.cpp index af2bfcca7f2e..2fa125075bd1 100644 --- a/dom/geolocation/GeolocationSystemWin.cpp +++ b/dom/geolocation/GeolocationSystemWin.cpp @@ -5,9 +5,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "GeolocationSystem.h" +#include "mozilla/Components.h" #include "mozilla/dom/BrowsingContext.h" #include "mozilla/ScopeExit.h" #include "nsIGeolocationUIUtilsWin.h" +#include "nsIWifiListener.h" #include "nsIWifiMonitor.h" #include @@ -70,10 +72,7 @@ bool SystemWillPromptForPermissionHint() { // If wifi is not available (e.g. because there is no wifi device present) // then the API may report that Windows will request geolocation permission // but it can't without the wifi scanner. Check for that case. - nsresult rv = NS_OK; - nsCOMPtr wifiMonitor = - do_GetService("@mozilla.org/wifi/monitor;1", &rv); - NS_ENSURE_SUCCESS(rv, false); + nsCOMPtr wifiMonitor = components::WifiMonitor::Service(); NS_ENSURE_TRUE(wifiMonitor, false); return wifiMonitor->GetHasWifiAdapter(); } @@ -268,6 +267,46 @@ void OpenWindowsLocationSettings( cancelRequest.release(); } +class LocationPermissionWifiScanListener final : public nsIWifiListener { + public: + NS_DECL_ISUPPORTS + + explicit LocationPermissionWifiScanListener( + SystemGeolocationPermissionRequest* aRequest) + : mRequest(aRequest) {} + + NS_IMETHOD OnChange(const nsTArray>&) override { + // We will remove ourselves from the nsIWifiMonitor, which is our owner. + // Hold a strong reference to ourselves until we complete the callback. + RefPtr self = this; + return PermissionWasDecided(); + } + + NS_IMETHOD OnError(nsresult) override { + // We will remove ourselves from the nsIWifiMonitor, which is our owner. + // Hold a strong reference to ourselves until we complete the callback. + RefPtr self = this; + return PermissionWasDecided(); + } + + private: + virtual ~LocationPermissionWifiScanListener() = default; + RefPtr mRequest; + + // Any response to our wifi scan request means that the user has selected + // either to grant or deny permission in the Windows dialog. Either way, we + // are done asking for permission, so Stop the permission request. + nsresult PermissionWasDecided() { + nsCOMPtr wifiMonitor = components::WifiMonitor::Service(); + NS_ENSURE_TRUE(wifiMonitor, NS_ERROR_FAILURE); + wifiMonitor->StopWatching(this); + mRequest->Stop(); + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(LocationPermissionWifiScanListener, nsIWifiListener) + } // namespace //----------------------------------------------------------------------------- @@ -282,8 +321,9 @@ SystemGeolocationPermissionBehavior GetGeolocationPermissionBehavior() { return SystemGeolocationPermissionBehavior::NoPrompt; } -already_AddRefed PresentSystemSettings( - BrowsingContext* aBrowsingContext, ParentRequestResolver&& aResolver) { +already_AddRefed +RequestLocationPermissionFromUser(BrowsingContext* aBrowsingContext, + ParentRequestResolver&& aResolver) { RefPtr permissionRequest = new WindowsGeolocationPermissionRequest(aBrowsingContext, std::move(aResolver)); @@ -291,7 +331,20 @@ already_AddRefed PresentSystemSettings( if (permissionRequest->IsStopped()) { return nullptr; } - OpenWindowsLocationSettings(permissionRequest); + if (SystemWillPromptForPermissionHint()) { + // To tell the system to prompt for permission, run one wifi scan (no need + // to poll). We won't use the result -- either the user will grant + // geolocation permission, meaning we will not need wifi scanning, or the + // user will deny permission, in which case no scan can be done. We just + // want the prompt. + nsCOMPtr wifiMonitor = components::WifiMonitor::Service(); + NS_ENSURE_TRUE(wifiMonitor, nullptr); + auto listener = + MakeRefPtr(permissionRequest); + wifiMonitor->StartWatching(listener, false); + } else { + OpenWindowsLocationSettings(permissionRequest); + } return permissionRequest.forget(); } diff --git a/netwerk/build/components.conf b/netwerk/build/components.conf index 2e7cbbd2e9a4..024e6f9ae90a 100644 --- a/netwerk/build/components.conf +++ b/netwerk/build/components.conf @@ -764,6 +764,7 @@ Classes = [ if defined('NECKO_WIFI'): Classes += [ { + 'name': 'WifiMonitor', 'cid': '{3ff8fb9f-ee63-48df-89f0-dace0242fd82}', 'contract_ids': ['@mozilla.org/wifi/monitor;1'], 'singleton': True,