Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/doc/ref/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.9.2025 mit Größe 8 kB image not shown  

Quelle  PortalLocationProvider.cpp   Sprache: C

 
/* -*- 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/. */


#include "PortalLocationProvider.h"
#include "MLSFallback.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/GeolocationPositionErrorBinding.h"
#include "GeolocationPosition.h"
#include "prtime.h"
#include "mozilla/GUniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/XREAppData.h"

#include <gio/gio.h>
#include <glib-object.h>

extern const mozilla::XREAppData* gAppData;

namespace mozilla::dom {

#ifdef MOZ_LOGGING
static LazyLogModule sPortalLog("Portal");
#  define LOG_PORTAL(...) MOZ_LOG(sPortalLog, LogLevel::Debug, (__VA_ARGS__))
#else
#  define LOG_PORTAL(...)
#endif /* MOZ_LOGGING */

const char kDesktopBusName[] = "org.freedesktop.portal.Desktop";
const char kSessionInterfaceName[] = "org.freedesktop.portal.Session";

/**
 * |MLSGeolocationUpdate| provides a fallback if Portal is not supported.
 */

class PortalLocationProvider::MLSGeolocationUpdate final
    : public nsIGeolocationUpdate {
 public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIGEOLOCATIONUPDATE

  explicit MLSGeolocationUpdate(nsIGeolocationUpdate* aCallback);

 protected:
  ~MLSGeolocationUpdate() = default;

 private:
  const nsCOMPtr<nsIGeolocationUpdate> mCallback;
};

PortalLocationProvider::MLSGeolocationUpdate::MLSGeolocationUpdate(
    nsIGeolocationUpdate* aCallback)
    : mCallback(aCallback) {
  MOZ_ASSERT(mCallback);
}

NS_IMPL_ISUPPORTS(PortalLocationProvider::MLSGeolocationUpdate,
                  nsIGeolocationUpdate);

// nsIGeolocationUpdate
//

NS_IMETHODIMP
PortalLocationProvider::MLSGeolocationUpdate::Update(
    nsIDOMGeoPosition* aPosition) {
  nsCOMPtr<nsIDOMGeoPositionCoords> coords;
  aPosition->GetCoords(getter_AddRefs(coords));
  if (!coords) {
    return NS_ERROR_FAILURE;
  }
  LOG_PORTAL("MLS is updating position\n");
  return mCallback->Update(aPosition);
}

NS_IMETHODIMP
PortalLocationProvider::MLSGeolocationUpdate::NotifyError(uint16_t aError) {
  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
  return callback->NotifyError(aError);
}

//
// PortalLocationProvider
//

PortalLocationProvider::PortalLocationProvider() = default;

PortalLocationProvider::~PortalLocationProvider() {
  if (mDBUSLocationProxy || mRefreshTimer || mMLSProvider) {
    NS_WARNING(
        "PortalLocationProvider: Shutdown() had not been called before "
        "destructor.");
    Shutdown();
  }
}

void PortalLocationProvider::Update(nsIDOMGeoPosition* aPosition) {
  if (!mCallback) {
    return;  // not initialized or already shut down
  }

  if (mMLSProvider) {
    LOG_PORTAL(
        "Update from location portal received: Cancelling fallback MLS "
        "provider\n");
    mMLSProvider->Shutdown(MLSFallback::ShutdownReason::ProviderResponded);
    mMLSProvider = nullptr;
  }

  LOG_PORTAL("Send updated location to the callback %p", mCallback.get());
  mCallback->Update(aPosition);

  aPosition->GetCoords(getter_AddRefs(mLastGeoPositionCoords));
  // Schedule sending repetitive updates because we don't get more until
  // position is changed from portal. That would lead to timeout on the
  // Firefox side.
  SetRefreshTimer(5000);
}

void PortalLocationProvider::NotifyError(int aError) {
  LOG_PORTAL("*****NotifyError %d\n", aError);
  if (!mCallback) {
    return;  // not initialized or already shut down
  }

  if (!mMLSProvider) {
    /* With Portal failed, we restart MLS. It will be canceled once we
     * get another location from Portal. Start it immediately.
     */

    mMLSProvider = MakeAndAddRef<MLSFallback>(0);
    mMLSProvider->Startup(new MLSGeolocationUpdate(mCallback));
  }

  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
  callback->NotifyError(aError);
}

NS_IMPL_ISUPPORTS(PortalLocationProvider, nsIGeolocationProvider)

static void location_updated_signal_cb(GDBusProxy* proxy, gchar* sender_name,
                                       gchar* signal_name, GVariant* parameters,
                                       gpointer user_data) {
  LOG_PORTAL("Signal: %s received from: %s\n", sender_name, signal_name);

  if (g_strcmp0(signal_name, "LocationUpdated")) {
    LOG_PORTAL("Unexpected signal %s received", signal_name);
    return;
  }

  auto* locationProvider = static_cast<PortalLocationProvider*>(user_data);
  RefPtr<GVariant> response_data;
  gchar* session_handle;
  g_variant_get(parameters, "(o@a{sv})", &session_handle,
                response_data.StartAssignment());
  if (!response_data) {
    LOG_PORTAL("Missing response data from portal\n");
    locationProvider->NotifyError(
        GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
    return;
  }
  LOG_PORTAL("Session handle: %s Response data: %s\n", session_handle,
             GUniquePtr<gchar>(g_variant_print(response_data, TRUE)).get());
  g_free(session_handle);

  double lat = 0;
  double lon = 0;
  if (!g_variant_lookup(response_data, "Latitude""d", &lat) ||
      !g_variant_lookup(response_data, "Longitude""d", &lon)) {
    locationProvider->NotifyError(
        GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
    return;
  }

  double alt = UnspecifiedNaN<double>();
  g_variant_lookup(response_data, "Altitude""d", &alt);
  double vError = 0;
  double hError = UnspecifiedNaN<double>();
  g_variant_lookup(response_data, "Accuracy""d", &hError);
  double heading = UnspecifiedNaN<double>();
  g_variant_lookup(response_data, "Heading""d", &heading);
  double speed = UnspecifiedNaN<double>();
  g_variant_lookup(response_data, "Speed""d", &speed);

  locationProvider->Update(new nsGeoPosition(lat, lon, alt, hError, vError,
                                             heading, speed,
                                             PR_Now() / PR_USEC_PER_MSEC));
}

NS_IMETHODIMP
PortalLocationProvider::Startup() {
  LOG_PORTAL("Starting location portal");
  if (mDBUSLocationProxy) {
    LOG_PORTAL("Proxy already started.\n");
    return NS_OK;
  }

  // Create dbus proxy for the Location portal
  GUniquePtr<GError> error;
  mDBUSLocationProxy = dont_AddRef(g_dbus_proxy_new_for_bus_sync(
      G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE,
      nullptr, /* GDBusInterfaceInfo */
      kDesktopBusName, "/org/freedesktop/portal/desktop",
      "org.freedesktop.portal.Location", nullptr, /* GCancellable */
      getter_Transfers(error)));
  if (!mDBUSLocationProxy) {
    g_printerr("Error creating location dbus proxy: %s\n", error->message);
    return NS_OK;  // fallback to MLS
  }

  // Listen to signals which will be send to us with the location data
  mDBUSSignalHandler =
      g_signal_connect(mDBUSLocationProxy, "g-signal",
                       G_CALLBACK(location_updated_signal_cb), this);

  // Call CreateSession of the location portal
  GVariantBuilder builder;

  nsAutoCString appName;
  gAppData->GetDBusAppName(appName);
  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
  g_variant_builder_add(&builder, "{sv}""session_handle_token",
                        g_variant_new_string(appName.get()));

  RefPtr<GVariant> result = dont_AddRef(g_dbus_proxy_call_sync(
      mDBUSLocationProxy, "CreateSession", g_variant_new("(a{sv})", &builder),
      G_DBUS_CALL_FLAGS_NONE, -1, nullptr, getter_Transfers(error)));

  g_variant_builder_clear(&builder);

  if (!result) {
    g_printerr("Error calling CreateSession method: %s\n", error->message);
    return NS_OK;  // fallback to MLS
  }

  // Start to listen to the location changes
  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);

  // TODO Use wayland:handle as described in
  // https://flatpak.github.io/xdg-desktop-portal/#parent_window
  const gchar* parent_window = "";
  gchar* portalSession;
  g_variant_get_child(result, 0, "o", &portalSession);
  mPortalSession.reset(portalSession);

  result = g_dbus_proxy_call_sync(
      mDBUSLocationProxy, "Start",
      g_variant_new("(osa{sv})", mPortalSession.get(), parent_window, &builder),
      G_DBUS_CALL_FLAGS_NONE, -1, nullptr, getter_Transfers(error));

  g_variant_builder_clear(&builder);

  if (!result) {
    g_printerr("Error calling Start method: %s\n", error->message);
    return NS_OK;  // fallback to MLS
  }
  return NS_OK;
}

NS_IMETHODIMP
PortalLocationProvider::Watch(nsIGeolocationUpdate* aCallback) {
  mCallback = aCallback;

  if (mLastGeoPositionCoords) {
    // We cannot immediately call the Update there becase the window is not
    // yet ready for that.
    LOG_PORTAL(
        "Update location in 1ms because we have the valid coords cached.");
    SetRefreshTimer(1);
    return NS_OK;
  }

  /* The MLS fallback will kick in after 12 seconds if portal
   * doesn't provide location information within time. Once we
   * see the first message from portal, the fallback will be
   * disabled in |Update|.
   */

  mMLSProvider = MakeAndAddRef<MLSFallback>(12000);
  mMLSProvider->Startup(new MLSGeolocationUpdate(aCallback));

  return NS_OK;
}

NS_IMETHODIMP PortalLocationProvider::GetName(nsACString& aName) {
  aName.AssignLiteral("PortalLocationProvider");
  return NS_OK;
}

void PortalLocationProvider::SetRefreshTimer(int aDelay) {
  LOG_PORTAL("SetRefreshTimer for %p to %d ms\n"this, aDelay);
  if (!mRefreshTimer) {
    NS_NewTimerWithCallback(getter_AddRefs(mRefreshTimer), this, aDelay,
                            nsITimer::TYPE_ONE_SHOT);
  } else {
    mRefreshTimer->Cancel();
    mRefreshTimer->InitWithCallback(this, aDelay, nsITimer::TYPE_ONE_SHOT);
  }
}

NS_IMETHODIMP
PortalLocationProvider::Notify(nsITimer* timer) {
  // We need to reschedule the timer because we won't get any update
  // from portal until the location is changed. That would cause
  // watchPosition to fail with TIMEOUT error.
  SetRefreshTimer(5000);
  if (mLastGeoPositionCoords) {
    LOG_PORTAL("Update location callback with latest coords.");
    mCallback->Update(
        new nsGeoPosition(mLastGeoPositionCoords, PR_Now() / PR_USEC_PER_MSEC));
  }
  return NS_OK;
}

NS_IMETHODIMP
PortalLocationProvider::Shutdown() {
  LOG_PORTAL("Shutdown location provider");
  if (mRefreshTimer) {
    mRefreshTimer->Cancel();
    mRefreshTimer = nullptr;
  }
  mLastGeoPositionCoords = nullptr;
  if (mDBUSLocationProxy) {
    g_signal_handler_disconnect(mDBUSLocationProxy, mDBUSSignalHandler);
    LOG_PORTAL("calling Close method to the session interface...\n");
    RefPtr<GDBusMessage> message = dont_AddRef(g_dbus_message_new_method_call(
        kDesktopBusName, mPortalSession.get(), kSessionInterfaceName, "Close"));
    mPortalSession = nullptr;
    if (message) {
      GUniquePtr<GError> error;
      GDBusConnection* connection =
          g_dbus_proxy_get_connection(mDBUSLocationProxy);
      g_dbus_connection_send_message(
          connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE,
          /*out_serial=*/nullptr, getter_Transfers(error));
      if (error) {
        g_printerr("Failed to close the session: %s\n", error->message);
      }
    }
    mDBUSLocationProxy = nullptr;
  }
  if (mMLSProvider) {
    mMLSProvider->Shutdown(MLSFallback::ShutdownReason::ProviderShutdown);
    mMLSProvider = nullptr;
  }
  return NS_OK;
}

NS_IMETHODIMP
PortalLocationProvider::SetHighAccuracy(bool aHigh) { return NS_OK; }

}  // namespace mozilla::dom

100%


¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.