diff --git a/default_app/default_app.ts b/default_app/default_app.ts index 6cd280bb555c0..9109eef1e0199 100644 --- a/default_app/default_app.ts +++ b/default_app/default_app.ts @@ -39,13 +39,29 @@ function isTrustedSender (webContents: Electron.WebContents) { } } +// Correct implementation +ipcMain.handle('get-current-position', async () => { + try { + // @ts-ignore + const position = await app.getCurrentPosition(); + return position; + } catch (error) { + console.error('Error getting location:', error); + throw error; + } +}); + +ipcMain.handle('request-geolocation-permission', () => { + // @ts-ignore + app.requestGeolocationPermission(); +}); + ipcMain.handle('bootstrap', (event) => { return isTrustedSender(event.sender) ? electronPath : null; }); async function createWindow (backgroundColor?: string) { await app.whenReady(); - const options: Electron.BrowserWindowConstructorOptions = { width: 960, height: 620, diff --git a/default_app/preload.ts b/default_app/preload.ts index fb6b9d4eaafb3..1bbe2079173c3 100644 --- a/default_app/preload.ts +++ b/default_app/preload.ts @@ -63,3 +63,11 @@ async function initialize () { contextBridge.exposeInMainWorld('electronDefaultApp', { initialize }); + +contextBridge.exposeInMainWorld('electron', { + // Create a geolocation property with its own methods + geolocation: { + getCurrentPosition: () => ipcRenderer.invoke('get-current-position'), + requestPermission: () => ipcRenderer.invoke('request-geolocation-permission') + } +}); diff --git a/filenames.gni b/filenames.gni index 7bd470eec7420..200016d66be3a 100644 --- a/filenames.gni +++ b/filenames.gni @@ -245,8 +245,8 @@ filenames = { "shell/app/node_main.h", "shell/app/uv_task_runner.cc", "shell/app/uv_task_runner.h", - "shell/browser/api/electron_api_app.cc", "shell/browser/api/electron_api_app.h", + "shell/browser/api/electron_api_app.mm", "shell/browser/api/electron_api_auto_updater.cc", "shell/browser/api/electron_api_auto_updater.h", "shell/browser/api/electron_api_base_window.cc", @@ -320,6 +320,8 @@ filenames = { "shell/browser/api/electron_api_web_view_manager.cc", "shell/browser/api/frame_subscriber.cc", "shell/browser/api/frame_subscriber.h", + "shell/browser/api/geolocation_manager.h", + "shell/browser/api/geolocation_manager.mm", "shell/browser/api/gpu_info_enumerator.cc", "shell/browser/api/gpu_info_enumerator.h", "shell/browser/api/gpuinfo_manager.cc", diff --git a/shell/browser/api/electron_api_app.h b/shell/browser/api/electron_api_app.h index 6a208950bd222..5bf3893e7168f 100644 --- a/shell/browser/api/electron_api_app.h +++ b/shell/browser/api/electron_api_app.h @@ -231,6 +231,8 @@ class App final : public ElectronBrowserClient::Delegate, v8::Local GetGPUFeatureStatus(v8::Isolate* isolate); v8::Local GetGPUInfo(v8::Isolate* isolate, const std::string& info_type); + void RequestGeolocationPermission(); + v8::Local GetCurrentPosition(gin::Arguments* args); void EnableSandbox(gin_helper::ErrorThrower thrower); void SetUserAgentFallback(const std::string& user_agent); std::string GetUserAgentFallback(); diff --git a/shell/browser/api/electron_api_app.cc b/shell/browser/api/electron_api_app.mm similarity index 96% rename from shell/browser/api/electron_api_app.cc rename to shell/browser/api/electron_api_app.mm index 1e311fbec49b0..9ea2d922c279d 100644 --- a/shell/browser/api/electron_api_app.cc +++ b/shell/browser/api/electron_api_app.mm @@ -54,6 +54,7 @@ #include "shell/browser/api/electron_api_menu.h" #include "shell/browser/api/electron_api_utility_process.h" #include "shell/browser/api/electron_api_web_contents.h" +#include "shell/browser/api/geolocation_manager.h" #include "shell/browser/api/gpuinfo_manager.h" #include "shell/browser/api/process_metric.h" #include "shell/browser/browser_process_impl.h" @@ -944,9 +945,8 @@ std::string App::GetLocale() { std::string App::GetSystemLocale(gin_helper::ErrorThrower thrower) const { if (!Browser::Get()->is_ready()) { - thrower.ThrowError( - "app.getSystemLocale() can only be called " - "after app is ready"); + thrower.ThrowError("app.getSystemLocale() can only be called " + "after app is ready"); return {}; } return static_cast(g_browser_process)->GetSystemLocale(); @@ -1108,9 +1108,8 @@ bool App::Relaunch(gin::Arguments* js_args) { void App::DisableHardwareAcceleration(gin_helper::ErrorThrower thrower) { if (Browser::Get()->is_ready()) { - thrower.ThrowError( - "app.disableHardwareAcceleration() can only be called " - "before app is ready"); + thrower.ThrowError("app.disableHardwareAcceleration() can only be called " + "before app is ready"); return; } if (content::GpuDataManager::Initialized()) { @@ -1397,6 +1396,45 @@ v8::Local App::GetGPUInfo(v8::Isolate* isolate, return handle; } +void App::RequestGeolocationPermission() { + // Get location manager that is set during startup + auto* permission_manager = + device::GeolocationSystemPermissionManager::GetInstance(); + auto& source_ref = permission_manager->GetSystemGeolocationSource(); + auto* source = + static_cast(&source_ref); + // Request permission + source->RequestPermission(); +} + +v8::Local App::GetCurrentPosition(gin::Arguments* args) { + v8::Isolate* isolate = args->isolate(); + + // Create a promise that will resolve with a the position object + gin_helper::Promise promise(isolate); + v8::Local handle = promise.GetHandle(); + + // Get location manager that is set during startup + auto* permission_manager = + device::GeolocationSystemPermissionManager::GetInstance(); + auto& source_ref = permission_manager->GetSystemGeolocationSource(); + auto* source = + static_cast(&source_ref); + + // Get the current location synchronously + auto [latitude, longitude] = source->GetCurrentLocation(); + + // Create position object only with latitude and longitude for now + gin_helper::Dictionary position = gin::Dictionary::CreateEmpty(isolate); + position.Set("latitude", latitude); + position.Set("longitude", longitude); + + // Resolve the promise with the position object + promise.Resolve(position); + + return handle; +} + static void RemoveNoSandboxSwitch(base::CommandLine* command_line) { if (command_line->HasSwitch(sandbox::policy::switches::kNoSandbox)) { const base::CommandLine::CharType* noSandboxArg = @@ -1413,9 +1451,8 @@ static void RemoveNoSandboxSwitch(base::CommandLine* command_line) { void App::EnableSandbox(gin_helper::ErrorThrower thrower) { if (Browser::Get()->is_ready()) { - thrower.ThrowError( - "app.enableSandbox() can only be called " - "before app is ready"); + thrower.ThrowError("app.enableSandbox() can only be called " + "before app is ready"); return; } @@ -1797,6 +1834,9 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) { .SetMethod("getAppMetrics", &App::GetAppMetrics) .SetMethod("getGPUFeatureStatus", &App::GetGPUFeatureStatus) .SetMethod("getGPUInfo", &App::GetGPUInfo) + .SetMethod("requestGeolocationPermission", + &App::RequestGeolocationPermission) + .SetMethod("getCurrentPosition", &App::GetCurrentPosition) #if IS_MAS_BUILD() .SetMethod("startAccessingSecurityScopedResource", &App::StartAccessingSecurityScopedResource) diff --git a/shell/browser/api/geolocation_manager.h b/shell/browser/api/geolocation_manager.h new file mode 100644 index 0000000000000..bc9588fa8dc28 --- /dev/null +++ b/shell/browser/api/geolocation_manager.h @@ -0,0 +1,34 @@ +// Copyright 2023 Your Name +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_SHELL_BROWSER_API_GEOLOCATION_MANAGER_H_ +#define ELECTRON_SHELL_BROWSER_API_GEOLOCATION_MANAGER_H_ + +#include "services/device/public/cpp/geolocation/system_geolocation_source_apple.h" + +@class CLLocationManager; +@class LocationManagerDelegate; + +namespace device { + +class SystemGeolocationSourceAppleCustom : public SystemGeolocationSourceApple { + public: + SystemGeolocationSourceAppleCustom(); + ~SystemGeolocationSourceAppleCustom() override; + + static std::unique_ptr + CreateGeolocationSystemPermissionManager(); + + void RequestPermission() override; + std::pair GetCurrentLocation(); + LocationSystemPermissionStatus GetCurrentSystemPermission() const; + + private: + CLLocationManager* __strong custom_location_manager; + LocationManagerDelegate* __strong custom_delegate; +}; + +} // namespace device + +#endif // GEOLOCATION_MANAGER_H_ diff --git a/shell/browser/api/geolocation_manager.mm b/shell/browser/api/geolocation_manager.mm new file mode 100644 index 0000000000000..74aea5445d81f --- /dev/null +++ b/shell/browser/api/geolocation_manager.mm @@ -0,0 +1,57 @@ +// Copyright 2023 Your Name +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "shell/browser/api/geolocation_manager.h" +#include "services/device/public/cpp/geolocation/location_manager_delegate.h" + +namespace device { + +SystemGeolocationSourceAppleCustom::SystemGeolocationSourceAppleCustom() + : SystemGeolocationSourceApple() { + custom_location_manager = [[CLLocationManager alloc] init]; + custom_delegate = SystemGeolocationSourceApple::GetDelegateForTesting(); + custom_location_manager.delegate = custom_delegate; + SystemGeolocationSourceApple::SetLocationManagerForTesting( + custom_location_manager); +} + +SystemGeolocationSourceAppleCustom::~SystemGeolocationSourceAppleCustom() = + default; + +// static +std::unique_ptr +SystemGeolocationSourceAppleCustom::CreateGeolocationSystemPermissionManager() { + return std::make_unique( + std::make_unique()); +} + +void SystemGeolocationSourceAppleCustom::RequestPermission() { + LocationSystemPermissionStatus status = GetCurrentSystemPermission(); + if (status == LocationSystemPermissionStatus::kNotDetermined) { + [custom_location_manager requestWhenInUseAuthorization]; + } else if (status == LocationSystemPermissionStatus::kDenied) { + OpenSystemPermissionSetting(); + } +} + +std::pair +SystemGeolocationSourceAppleCustom::GetCurrentLocation() { + RequestPermission(); + double latitude = [custom_location_manager location].coordinate.latitude; + double longitude = [custom_location_manager location].coordinate.longitude; + return {latitude, longitude}; +} + +LocationSystemPermissionStatus +SystemGeolocationSourceAppleCustom::GetCurrentSystemPermission() const { + if (![custom_delegate permissionInitialized]) { + return LocationSystemPermissionStatus::kNotDetermined; + } + if ([custom_delegate hasPermission]) { + return LocationSystemPermissionStatus::kAllowed; + } + return LocationSystemPermissionStatus::kDenied; +} + +} // namespace device diff --git a/shell/browser/electron_browser_main_parts_mac.mm b/shell/browser/electron_browser_main_parts_mac.mm index c7c093010ef0b..888b58df65b4d 100644 --- a/shell/browser/electron_browser_main_parts_mac.mm +++ b/shell/browser/electron_browser_main_parts_mac.mm @@ -10,11 +10,11 @@ #include "base/apple/foundation_util.h" #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h" #include "services/device/public/cpp/geolocation/system_geolocation_source_apple.h" +#include "shell/browser/api/geolocation_manager.h" #include "shell/browser/browser_process_impl.h" #include "shell/browser/mac/electron_application.h" #include "shell/browser/mac/electron_application_delegate.h" #include "ui/base/l10n/l10n_util_mac.h" - namespace electron { static ElectronApplicationDelegate* __strong delegate_; @@ -34,7 +34,7 @@ if (!device::GeolocationSystemPermissionManager::GetInstance()) { device::GeolocationSystemPermissionManager::SetInstance( - device::SystemGeolocationSourceApple:: + device::SystemGeolocationSourceAppleCustom:: CreateGeolocationSystemPermissionManager()); } }