/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
bool SystemWillPromptForPermissionHint() { auto wifiAccess = GetWifiControlAccess(); if (wifiAccess !=
mozilla::Some(AppCapabilityAccessStatus::
AppCapabilityAccessStatus_UserPromptRequired)) { returnfalse;
}
// 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.
nsCOMPtr<nsIWifiMonitor> wifiMonitor = components::WifiMonitor::Service();
NS_ENSURE_TRUE(wifiMonitor, false); return wifiMonitor->GetHasWifiAdapter();
}
bool LocationIsPermittedHint() { auto wifiAccess = GetWifiControlAccess(); // This API wasn't available on earlier versions of Windows, so a failure to // get the result means that we will assume that location access is permitted. return wifiAccess.isNothing() ||
*wifiAccess ==
AppCapabilityAccessStatus::AppCapabilityAccessStatus_Allowed;
}
class WindowsGeolocationPermissionRequest final
: public SystemGeolocationPermissionRequest, public SupportsThreadSafeWeakPtr<WindowsGeolocationPermissionRequest> { public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(WindowsGeolocationPermissionRequest); // Define SystemGeolocationPermissionRequest's ref-counting by forwarding the // calls to SupportsThreadSafeWeakPtr<WindowsGeolocationPermissionRequest>
NS_INLINE_DECL_REFCOUNTING_INHERITED(
WindowsGeolocationPermissionRequest,
SupportsThreadSafeWeakPtr<WindowsGeolocationPermissionRequest>);
mAppCapability = GetWifiControlAppCapability(); if (!mAppCapability) { return;
}
using AccessChangedHandler =
ITypedEventHandler<AppCapability*,
AppCapabilityAccessChangedEventArgs*>;
// Note: This creates the callback that listens for location permission // changes as free threaded, which we need to do to overcome a (Microsoft) // issue with the callback proxy's exports with (at least) the pre-24H2 // versions of Windows.
ComPtr<AccessChangedHandler> acHandlerRef = Callback<Implements<
RuntimeClassFlags<ClassicCom>, AccessChangedHandler, FtmBase>>(
[weakSelf = ThreadSafeWeakPtr<WindowsGeolocationPermissionRequest>( this)](IAppCapability*, IAppCapabilityAccessChangedEventArgs*) { // Because of the free threaded access mentioned above, our // callback can run on a background thread, so dispatch it to // main. if (!NS_IsMainThread()) {
NS_DispatchToMainThread(
NS_NewRunnableFunction(__func__, [weakSelf]() {
RefPtr<WindowsGeolocationPermissionRequest> self(weakSelf); if (self) {
self->StopIfLocationIsPermitted();
}
})); return S_OK;
}
RefPtr<WindowsGeolocationPermissionRequest> self(weakSelf); if (self) {
self->StopIfLocationIsPermitted();
} return S_OK;
});
protected: // Ref-counting demands that the destructor be non-public but // SupportsThreadSafeWeakPtr needs to be able to call it, because we use // NS_INLINE_DECL_REFCOUNTING_INHERITED. friend SupportsThreadSafeWeakPtr<WindowsGeolocationPermissionRequest>;
// This IAppCapability object must be held for the duration of the period // where we listen for location permission changes or else the callback // will not be called.
RefPtr<IAppCapability> mAppCapability;
ParentRequestResolver mResolver;
RefPtr<BrowsingContext> mBrowsingContext;
EventRegistrationToken mToken; bool mIsRunning = false;
};
// Opens Windows geolocation settings and cancels the geolocation request on // error. void OpenWindowsLocationSettings(
SystemGeolocationPermissionRequest* aPermissionRequest) { auto cancelRequest = MakeScopeExit([&]() { aPermissionRequest->Stop(); });
// The IAsyncOperation is similar to a promise so there is no race here, // despite us adding this callback after requesting launch instead of before.
handler->put_Completed(
Callback<IAsyncOperationCompletedHandler<bool>>(
[permissionRequest = RefPtr{aPermissionRequest}](
IAsyncOperation<bool>* asyncInfo, AsyncStatus status) { unsignedchar verdict = 0;
asyncInfo->GetResults(&verdict); if (!verdict) {
permissionRequest->Stop();
} return S_OK;
})
.Get());
cancelRequest.release();
}
class LocationPermissionWifiScanListener final : public nsIWifiListener { public:
NS_DECL_ISUPPORTS
NS_IMETHOD OnChange(const nsTArray<RefPtr<nsIWifiAccessPoint>>&) override { // We will remove ourselves from the nsIWifiMonitor, which is our owner. // Hold a strong reference to ourselves until we complete the callback.
RefPtr<LocationPermissionWifiScanListener> 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<LocationPermissionWifiScanListener> self = this; return PermissionWasDecided();
}
// 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<nsIWifiMonitor> wifiMonitor = components::WifiMonitor::Service();
NS_ENSURE_TRUE(wifiMonitor, NS_ERROR_FAILURE);
wifiMonitor->StopWatching(this);
mRequest->Stop(); return NS_OK;
}
};
SystemGeolocationPermissionBehavior GetGeolocationPermissionBehavior() { if (SystemWillPromptForPermissionHint()) { return SystemGeolocationPermissionBehavior::SystemWillPromptUser;
} if (!LocationIsPermittedHint()) { return SystemGeolocationPermissionBehavior::GeckoWillPromptUser;
} return SystemGeolocationPermissionBehavior::NoPrompt;
}
already_AddRefed<SystemGeolocationPermissionRequest>
RequestLocationPermissionFromUser(BrowsingContext* aBrowsingContext,
ParentRequestResolver&& aResolver) {
RefPtr<WindowsGeolocationPermissionRequest> permissionRequest = new WindowsGeolocationPermissionRequest(aBrowsingContext,
std::move(aResolver));
permissionRequest->Initialize(); if (permissionRequest->IsStopped()) { return nullptr;
} 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<nsIWifiMonitor> wifiMonitor = components::WifiMonitor::Service();
NS_ENSURE_TRUE(wifiMonitor, nullptr); auto listener =
MakeRefPtr<LocationPermissionWifiScanListener>(permissionRequest);
wifiMonitor->StartWatching(listener, false);
} else {
OpenWindowsLocationSettings(permissionRequest);
} return permissionRequest.forget();
}
} // namespace mozilla::dom::geolocation
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.