From 219f661a74c713ee9c1cb15cd68a6fcd708c29b6 Mon Sep 17 00:00:00 2001 From: Simon Hong Date: Wed, 8 May 2024 09:35:18 +0900 Subject: [PATCH] Update Geolocation permission bubble (#23278) * Update Geolocation permission dialog fix https://github.com/brave/brave-browser/issues/16897 Added more information to users for getting precise location. --------- Co-authored-by: Brian Clifton --- app/brave_generated_resources.grd | 12 ++ browser/brave_content_browser_client.cc | 13 ++ browser/brave_tab_helpers.cc | 2 + browser/ui/BUILD.gn | 23 +++ browser/ui/geolocation/BUILD.gn | 24 +++ .../brave_geolocation_browsertest.cc | 80 ++++++++ ...brave_geolocation_permission_tab_helper.cc | 52 +++++ .../brave_geolocation_permission_tab_helper.h | 45 +++++ browser/ui/geolocation/geolocation_utils.h | 21 +++ .../ui/geolocation/geolocation_utils_linux.cc | 18 ++ .../ui/geolocation/geolocation_utils_mac.mm | 49 +++++ .../ui/geolocation/geolocation_utils_win.cc | 71 +++++++ .../permission_prompt_bubble_base_view.cc | 178 +++++++++++++++++- .../blink/renderer/modules/geolocation/DEPS | 3 + .../modules/geolocation/geolocation.cc | 54 ++++++ .../common/BUILD.gn | 14 ++ .../common/brave_geolocation_permission.mojom | 10 + .../resources/brave_components_strings.grd | 4 + test/BUILD.gn | 1 + third_party/blink/renderer/includes.gni | 4 + 20 files changed, 677 insertions(+), 1 deletion(-) create mode 100644 browser/ui/geolocation/BUILD.gn create mode 100644 browser/ui/geolocation/brave_geolocation_browsertest.cc create mode 100644 browser/ui/geolocation/brave_geolocation_permission_tab_helper.cc create mode 100644 browser/ui/geolocation/brave_geolocation_permission_tab_helper.h create mode 100644 browser/ui/geolocation/geolocation_utils.h create mode 100644 browser/ui/geolocation/geolocation_utils_linux.cc create mode 100644 browser/ui/geolocation/geolocation_utils_mac.mm create mode 100644 browser/ui/geolocation/geolocation_utils_win.cc create mode 100644 chromium_src/third_party/blink/renderer/modules/geolocation/DEPS create mode 100644 chromium_src/third_party/blink/renderer/modules/geolocation/geolocation.cc create mode 100644 components/brave_geolocation_permission/common/BUILD.gn create mode 100644 components/brave_geolocation_permission/common/brave_geolocation_permission.mojom diff --git a/app/brave_generated_resources.grd b/app/brave_generated_resources.grd index 1d5c1e1894df..73605ef8f1bc 100644 --- a/app/brave_generated_resources.grd +++ b/app/brave_generated_resources.grd @@ -557,6 +557,18 @@ Or change later at $2brave://settings/ext this setting + + + + This site has requested your $1general location$1. $1Learn more$1 + + + This site has requested your $1precise location$1. $1Learn more$1 + + + This site has requested your $1precise location$1. Brave will only able to provide $1general location$1 data due to $1Location Services$1 being disabled. $1Learn more$1 + + Close all diff --git a/browser/brave_content_browser_client.cc b/browser/brave_content_browser_client.cc index 51297818dfe1..a6f432435d0d 100644 --- a/browser/brave_content_browser_client.cc +++ b/browser/brave_content_browser_client.cc @@ -220,6 +220,7 @@ using extensions::ChromeContentBrowserClientExtensionsPart; #if !BUILDFLAG(IS_ANDROID) #include "brave/browser/new_tab/new_tab_shows_navigation_throttle.h" +#include "brave/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h" #include "brave/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h" #include "brave/browser/ui/webui/brave_rewards/rewards_panel_ui.h" #include "brave/browser/ui/webui/brave_rewards/tip_panel_ui.h" @@ -564,6 +565,18 @@ void BraveContentBrowserClient:: &render_frame_host)); #endif // BUILDFLAG(ENABLE_WIDEVINE) +#if !BUILDFLAG(IS_ANDROID) + associated_registry.AddInterface< + geolocation::mojom::BraveGeolocationPermission>(base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver< + geolocation::mojom::BraveGeolocationPermission> receiver) { + BraveGeolocationPermissionTabHelper::BindBraveGeolocationPermission( + std::move(receiver), render_frame_host); + }, + &render_frame_host)); +#endif // !BUILDFLAG(IS_ANDROID) + associated_registry.AddInterface< brave_shields::mojom::BraveShieldsHost>(base::BindRepeating( [](content::RenderFrameHost* render_frame_host, diff --git a/browser/brave_tab_helpers.cc b/browser/brave_tab_helpers.cc index 0006f81eb71c..bf4f21270b47 100644 --- a/browser/brave_tab_helpers.cc +++ b/browser/brave_tab_helpers.cc @@ -56,6 +56,7 @@ #if !BUILDFLAG(IS_ANDROID) #include "brave/browser/ui/brave_shields_data_controller.h" +#include "brave/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h" #include "chrome/browser/ui/thumbnails/thumbnail_tab_helper.h" #endif @@ -131,6 +132,7 @@ void AttachTabHelpers(content::WebContents* web_contents) { BraveBookmarkTabHelper::CreateForWebContents(web_contents); brave_shields::BraveShieldsDataController::CreateForWebContents(web_contents); ThumbnailTabHelper::CreateForWebContents(web_contents); + BraveGeolocationPermissionTabHelper::CreateForWebContents(web_contents); #endif brave_rewards::RewardsTabHelper::CreateForWebContents(web_contents); diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index d95c3c2d637a..525a53f31a5d 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -609,6 +609,29 @@ source_set("ui") { ] } + if (is_win || is_mac || is_linux) { + sources += [ + "geolocation/brave_geolocation_permission_tab_helper.cc", + "geolocation/brave_geolocation_permission_tab_helper.h", + "geolocation/geolocation_utils.h", + ] + + deps += [ "//brave/components/brave_geolocation_permission/common:brave_geolocation_permission" ] + + if (is_win) { + sources += [ "geolocation/geolocation_utils_win.cc" ] + } + + if (is_mac) { + sources += [ "geolocation/geolocation_utils_mac.mm" ] + frameworks = [ "CoreLocation.framework" ] + } + + if (is_linux) { + sources += [ "geolocation/geolocation_utils_linux.cc" ] + } + } + # brave's obsolete infobar is only used on Windows and Mac now. if (is_win || is_mac) { sources += [ diff --git a/browser/ui/geolocation/BUILD.gn b/browser/ui/geolocation/BUILD.gn new file mode 100644 index 000000000000..933cb423765e --- /dev/null +++ b/browser/ui/geolocation/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (c) 2024 The Brave Authors. All rights reserved. +# 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 https://mozilla.org/MPL/2.0/. + +assert(!is_android) + +source_set("browser_tests") { + testonly = true + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + + sources = [ "brave_geolocation_browsertest.cc" ] + deps = [ + "//base", + "//brave/components/constants", + "//chrome/browser", + "//chrome/browser/ui", + "//chrome/common:constants", + "//chrome/test:test_support_ui", + "//content/test:test_support", + "//net:test_support", + "//url", + ] +} diff --git a/browser/ui/geolocation/brave_geolocation_browsertest.cc b/browser/ui/geolocation/brave_geolocation_browsertest.cc new file mode 100644 index 000000000000..f89fc8668bff --- /dev/null +++ b/browser/ui/geolocation/brave_geolocation_browsertest.cc @@ -0,0 +1,80 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include + +#include "base/path_service.h" +#include "brave/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h" +#include "brave/components/constants/brave_paths.h" +#include "chrome/browser/ssl/cert_verifier_browser_test.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" +#include "content/public/test/test_utils.h" +#include "net/dns/mock_host_resolver.h" +#include "url/gurl.h" + +class GeolocationPermissionRequestBrowserTest : public CertVerifierBrowserTest { + public: + GeolocationPermissionRequestBrowserTest() + : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + + void SetUpOnMainThread() override { + CertVerifierBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + brave::RegisterPathProvider(); + base::FilePath test_data_dir = + base::PathService::CheckedGet(brave::DIR_TEST_DATA); + https_server_.ServeFilesFromDirectory(test_data_dir); + mock_cert_verifier()->set_default_result(net::OK); + + ASSERT_TRUE(https_server_.Start()); + } + + content::WebContents* active_contents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } + + protected: + net::EmbeddedTestServer https_server_; +}; + +IN_PROC_BROWSER_TEST_F(GeolocationPermissionRequestBrowserTest, + SetEnableHighAccuracyTest) { + GURL url = https_server_.GetURL("a.com", "/simple.html"); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + + auto* tab_helper = + BraveGeolocationPermissionTabHelper::FromWebContents(active_contents()); + EXPECT_FALSE(tab_helper->enable_high_accuracy()); + + const std::string get_current_position_js_with_high = + "navigator.geolocation.getCurrentPosition(() => {}, () => {}, { " + "enableHighAccuracy : true })"; + ASSERT_EQ(nullptr, content::EvalJs(active_contents(), + get_current_position_js_with_high)); + content::RunAllTasksUntilIdle(); + EXPECT_TRUE(tab_helper->enable_high_accuracy()); + + // Reload clear high_accuracy bit from tab helper. + content::TestNavigationObserver observer(active_contents()); + chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB); + observer.Wait(); + EXPECT_FALSE(tab_helper->enable_high_accuracy()); + + const std::string get_current_position_js_without_high = + "navigator.geolocation.getCurrentPosition(() => {}, () => {}, { " + "enableHighAccuracy : false })"; + ASSERT_EQ(nullptr, content::EvalJs(active_contents(), + get_current_position_js_without_high)); + content::RunAllTasksUntilIdle(); + EXPECT_FALSE(tab_helper->enable_high_accuracy()); +} diff --git a/browser/ui/geolocation/brave_geolocation_permission_tab_helper.cc b/browser/ui/geolocation/brave_geolocation_permission_tab_helper.cc new file mode 100644 index 000000000000..bfde8c5dcb89 --- /dev/null +++ b/browser/ui/geolocation/brave_geolocation_permission_tab_helper.cc @@ -0,0 +1,52 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h" + +#include + +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/web_contents.h" + +BraveGeolocationPermissionTabHelper::BraveGeolocationPermissionTabHelper( + content::WebContents* contents) + : WebContentsObserver(contents), + content::WebContentsUserData( + *contents), + brave_geolocation_permission_receivers_(contents, this) {} + +BraveGeolocationPermissionTabHelper::~BraveGeolocationPermissionTabHelper() = + default; + +// static +void BraveGeolocationPermissionTabHelper::BindBraveGeolocationPermission( + mojo::PendingAssociatedReceiver< + geolocation::mojom::BraveGeolocationPermission> receiver, + content::RenderFrameHost* rfh) { + auto* web_contents = content::WebContents::FromRenderFrameHost(rfh); + if (!web_contents) { + return; + } + + auto* tab_helper = + BraveGeolocationPermissionTabHelper::FromWebContents(web_contents); + if (!tab_helper) { + return; + } + tab_helper->brave_geolocation_permission_receivers_.Bind(rfh, + std::move(receiver)); +} + +void BraveGeolocationPermissionTabHelper::PrimaryPageChanged( + content::Page& page) { + enable_high_accuracy_ = false; +} + +void BraveGeolocationPermissionTabHelper::SetEnableHighAccuracy( + bool enable_high_accuracy) { + enable_high_accuracy_ = enable_high_accuracy; +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(BraveGeolocationPermissionTabHelper); diff --git a/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h b/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h new file mode 100644 index 000000000000..a9490b8e0314 --- /dev/null +++ b/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_UI_GEOLOCATION_BRAVE_GEOLOCATION_PERMISSION_TAB_HELPER_H_ +#define BRAVE_BROWSER_UI_GEOLOCATION_BRAVE_GEOLOCATION_PERMISSION_TAB_HELPER_H_ + +#include "brave/components/brave_geolocation_permission/common/brave_geolocation_permission.mojom.h" +#include "content/public/browser/render_frame_host_receiver_set.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +class BraveGeolocationPermissionTabHelper final + : public content::WebContentsObserver, + public geolocation::mojom::BraveGeolocationPermission, + public content::WebContentsUserData { + public: + explicit BraveGeolocationPermissionTabHelper(content::WebContents* contents); + ~BraveGeolocationPermissionTabHelper() override; + + static void BindBraveGeolocationPermission( + mojo::PendingAssociatedReceiver< + geolocation::mojom::BraveGeolocationPermission> receiver, + content::RenderFrameHost* rfh); + + // content::WebContentsObserver + void PrimaryPageChanged(content::Page& page) override; + + // geolocation::mojom::BraveGeolocationPermission overrides: + void SetEnableHighAccuracy(bool high_accuracy) override; + + bool enable_high_accuracy() const { return enable_high_accuracy_; } + + WEB_CONTENTS_USER_DATA_KEY_DECL(); + + private: + content::RenderFrameHostReceiverSet< + geolocation::mojom::BraveGeolocationPermission> + brave_geolocation_permission_receivers_; + + bool enable_high_accuracy_ = false; +}; + +#endif // BRAVE_BROWSER_UI_GEOLOCATION_BRAVE_GEOLOCATION_PERMISSION_TAB_HELPER_H_ diff --git a/browser/ui/geolocation/geolocation_utils.h b/browser/ui/geolocation/geolocation_utils.h new file mode 100644 index 000000000000..7990c831d007 --- /dev/null +++ b/browser/ui/geolocation/geolocation_utils.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_UI_GEOLOCATION_GEOLOCATION_UTILS_H_ +#define BRAVE_BROWSER_UI_GEOLOCATION_GEOLOCATION_UTILS_H_ + +#include "base/functional/callback_forward.h" + +namespace geolocation { + +// Run |callback| with true when system location service is available to +// applications. +void IsSystemLocationSettingEnabled(base::OnceCallback callback); + +bool CanGiveDetailedGeolocationRequestInfo(); + +} // namespace geolocation + +#endif // BRAVE_BROWSER_UI_GEOLOCATION_GEOLOCATION_UTILS_H_ diff --git a/browser/ui/geolocation/geolocation_utils_linux.cc b/browser/ui/geolocation/geolocation_utils_linux.cc new file mode 100644 index 000000000000..c689c6082c57 --- /dev/null +++ b/browser/ui/geolocation/geolocation_utils_linux.cc @@ -0,0 +1,18 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/geolocation/geolocation_utils.h" + +#include "base/functional/callback.h" + +namespace geolocation { + +void IsSystemLocationSettingEnabled(base::OnceCallback callback) {} + +bool CanGiveDetailedGeolocationRequestInfo() { + return false; +} + +} // namespace geolocation diff --git a/browser/ui/geolocation/geolocation_utils_mac.mm b/browser/ui/geolocation/geolocation_utils_mac.mm new file mode 100644 index 000000000000..60eb9c99a0bb --- /dev/null +++ b/browser/ui/geolocation/geolocation_utils_mac.mm @@ -0,0 +1,49 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/geolocation/geolocation_utils.h" + +#import + +#include + +#include "base/functional/callback.h" + +namespace geolocation { + +namespace { + +bool GetSystemLocationSettingEnabled() { + // Service is off globally. + if (![CLLocationManager locationServicesEnabled]) { + return false; + } + + if (@available(macOS 11.0, *)) { + CLLocationManager* manager = [[CLLocationManager alloc] init]; + if ([manager authorizationStatus] == + kCLAuthorizationStatusAuthorizedAlways) { + return true; + } + } + + return false; +} + +} // namespace + +void IsSystemLocationSettingEnabled(base::OnceCallback callback) { + std::move(callback).Run(GetSystemLocationSettingEnabled()); +} + +bool CanGiveDetailedGeolocationRequestInfo() { + if (@available(macOS 11.0, *)) { + return true; + } + + return false; +} + +} // namespace geolocation diff --git a/browser/ui/geolocation/geolocation_utils_win.cc b/browser/ui/geolocation/geolocation_utils_win.cc new file mode 100644 index 000000000000..90a55037c56a --- /dev/null +++ b/browser/ui/geolocation/geolocation_utils_win.cc @@ -0,0 +1,71 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/geolocation/geolocation_utils.h" + +#include + +#include +#include +#include + +#include + +#include "base/functional/callback.h" +#include "base/logging.h" +#include "base/task/thread_pool.h" +#include "base/win/core_winrt_util.h" + +using ABI::Windows::Devices::Enumeration::DeviceAccessStatus; +using ABI::Windows::Devices::Enumeration::DeviceClass; +using ABI::Windows::Devices::Enumeration::IDeviceAccessInformation; +using ABI::Windows::Devices::Enumeration::IDeviceAccessInformationStatics; +using Microsoft::WRL::ComPtr; + +namespace geolocation { + +namespace { + +// Copied from services/device/geolocation/win/location_provider_winrt.cc +bool GetSystemLocationSettingEnabled() { + ComPtr dev_access_info_statics; + HRESULT hr = base::win::GetActivationFactory< + IDeviceAccessInformationStatics, + RuntimeClass_Windows_Devices_Enumeration_DeviceAccessInformation>( + &dev_access_info_statics); + if (FAILED(hr)) { + VLOG(1) << "IDeviceAccessInformationStatics failed: " << hr; + return true; + } + + ComPtr dev_access_info; + hr = dev_access_info_statics->CreateFromDeviceClass( + DeviceClass::DeviceClass_Location, &dev_access_info); + if (FAILED(hr)) { + VLOG(1) << "IDeviceAccessInformation failed: " << hr; + return true; + } + + auto status = DeviceAccessStatus::DeviceAccessStatus_Unspecified; + dev_access_info->get_CurrentStatus(&status); + + return !(status == DeviceAccessStatus::DeviceAccessStatus_DeniedBySystem || + status == DeviceAccessStatus::DeviceAccessStatus_DeniedByUser); +} + +} // namespace + +void IsSystemLocationSettingEnabled(base::OnceCallback callback) { + base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()}) + ->PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&GetSystemLocationSettingEnabled), + std::move(callback)); +} + +bool CanGiveDetailedGeolocationRequestInfo() { + return true; +} + +} // namespace geolocation diff --git a/chromium_src/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc b/chromium_src/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc index 9b4529c3c8db..ac3c558c0014 100644 --- a/chromium_src/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc +++ b/chromium_src/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc @@ -3,17 +3,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at https://mozilla.org/MPL/2.0/. */ +#include "chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.h" + #include #include "base/feature_list.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_ref.h" +#include "brave/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h" +#include "brave/browser/ui/geolocation/geolocation_utils.h" #include "brave/browser/ui/views/dialog_footnote_utils.h" +#include "brave/browser/ui/views/infobars/custom_styled_label.h" #include "brave/components/constants/url_constants.h" #include "brave/components/constants/webui_url_constants.h" #include "brave/components/l10n/common/localization_util.h" #include "brave/components/permissions/permission_lifetime_utils.h" #include "brave/components/permissions/permission_widevine_utils.h" +#include "brave/components/vector_icons/vector_icons.h" #include "brave/grit/brave_generated_resources.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" @@ -28,13 +34,16 @@ #include "components/permissions/request_type.h" #include "components/strings/grit/components_strings.h" #include "third_party/widevine/cdm/buildflags.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/models/combobox_model.h" +#include "ui/base/models/image_model.h" #include "ui/gfx/text_constants.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/controls/button/checkbox.h" #include "ui/views/controls/combobox/combobox.h" +#include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/styled_label.h" #include "ui/views/layout/box_layout.h" @@ -48,6 +57,19 @@ namespace { +constexpr char kGeolocationPermissionLearnMoreURL[] = +#if BUILDFLAG(IS_WIN) + "https://support.microsoft.com/en-us/windows/" + "windows-location-service-and-privacy-3a8eee0a-5b0b-dc07-eede-" + "2a5ca1c49088"; +#elif BUILDFLAG(IS_MAC) + "https://support.apple.com/guide/mac-help/" + "allow-apps-to-detect-the-location-of-your-mac-mh35873/mac"; +#else + // Not used now. Set proper link when detailed bubble is enabled on linux. + "https://www.brave.com/"; +#endif + #if BUILDFLAG(ENABLE_WIDEVINE) class DontAskAgainCheckbox : public views::Checkbox { METADATA_HEADER(DontAskAgainCheckbox, views::Checkbox) @@ -176,6 +198,159 @@ class PermissionLifetimeCombobox : public views::Combobox, BEGIN_METADATA(PermissionLifetimeCombobox) END_METADATA +std::unique_ptr CreateGeolocationDescLabel( + Browser* browser, + bool enable_high_accuracy, + bool location_service_is_on) { + // The text shown in dialog is different depending on if person has location + // services enabled or disabled. This code finds which placeholders should + // show. + int string_id = IDS_GEOLOCATION_PERMISSION_BUBBLE_LOW_ACCURACY_LABEL; + size_t expected_offset_size = 4; + if (enable_high_accuracy && location_service_is_on) { + string_id = + IDS_GEOLOCATION_PERMISSION_BUBBLE_HIGH_ACCURACY_WITH_LOCATION_SERVICE_LABEL; + } else if (enable_high_accuracy) { + string_id = + IDS_GEOLOCATION_PERMISSION_BUBBLE_HIGH_ACCURACY_WITHOUT_LOCATION_SERVICE_LABEL; + expected_offset_size = 8; + } + + // This code will get the actual strings so we know the length/offset of each + // styles (bold, italics, etc) can be applied with a range (begin offset / end + // offset). + std::vector offsets; + const std::u16string contents_text = + l10n_util::GetStringFUTF16(string_id, {u""}, &offsets); + CHECK(!contents_text.empty()); + CHECK_EQ(expected_offset_size, offsets.size()); + + // Insert the placeholder text with styles. + auto contents_label = std::make_unique(); + contents_label->SetTextContext(views::style::CONTEXT_LABEL); + contents_label->SetDefaultTextStyle(views::style::STYLE_PRIMARY); + contents_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + contents_label->SetText(contents_text); + views::StyledLabel::RangeStyleInfo part_style; + part_style.text_style = views::style::STYLE_EMPHASIZED; + const int part_count_except_learn_more = offsets.size() / 2 - 1; + for (int i = 0; i < part_count_except_learn_more; ++i) { + // Each part has start/end offset pair. + const int part_start_offset = i * 2; + contents_label->AddStyleRange( + gfx::Range(offsets[part_start_offset], offsets[part_start_offset + 1]), + part_style); + } + + // It's ok to use |browser| in the link's callback as bubbble is tied with + // that |browser| and bubble is destroyed earlier than browser. + views::StyledLabel::RangeStyleInfo learn_more_style = + views::StyledLabel::RangeStyleInfo::CreateForLink(base::BindRepeating( + [](Browser* browser) { + chrome::AddSelectedTabWithURL( + browser, GURL(kGeolocationPermissionLearnMoreURL), + ui::PAGE_TRANSITION_AUTO_TOPLEVEL); + }, + browser)); + + // Learn more is last part. + const int learn_more_offset = offsets.size() - 2; + contents_label->AddStyleRange( + gfx::Range(offsets[learn_more_offset], offsets[learn_more_offset + 1]), + learn_more_style); + constexpr int kFixedLabelWidth = 290; + contents_label->SizeToFit(kFixedLabelWidth); + return contents_label; +} + +std::unique_ptr CreateGeolocationDescIcon( + bool enable_high_accuracy, + bool location_service_is_on) { + const bool use_high_accuracy = enable_high_accuracy && location_service_is_on; + constexpr int kIconSize = 16; + auto icon_view = + std::make_unique(ui::ImageModel::FromVectorIcon( + use_high_accuracy ? kLeoWarningTriangleOutlineIcon + : kLeoInfoOutlineIcon, + ui::ColorIds::kColorMenuIcon, kIconSize)); + // To align with text more precisely. + icon_view->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(2, 0, 0, 0))); + return icon_view; +} + +void AddGeolocationDescription( + views::BubbleDialogDelegateView* dialog_delegate_view, + Browser* browser, + bool enable_high_accuracy, + bool location_service_is_on) { + auto container = std::make_unique(); + constexpr int kPadding = 12; + constexpr int kChildSpacing = 6; + container + ->SetLayoutManager(std::make_unique( + views::BoxLayout::Orientation::kHorizontal, + gfx::Insets::TLBR(kPadding, 0, 0, 0), kChildSpacing)) + ->set_cross_axis_alignment(views::BoxLayout::CrossAxisAlignment::kStart); + + container->AddChildView( + CreateGeolocationDescIcon(enable_high_accuracy, location_service_is_on)); + container->AddChildView(CreateGeolocationDescLabel( + browser, enable_high_accuracy, location_service_is_on)); + dialog_delegate_view->AddChildView(std::move(container)); +} + +void AddGeolocationDescriptionIfNeeded( + PermissionPromptBubbleBaseView* bubble_base_view, + permissions::PermissionPrompt::Delegate* delegate, + Browser* browser) { + if (!geolocation::CanGiveDetailedGeolocationRequestInfo()) { + return; + } + + // Could be nullptr in unit test. + if (!browser) { + return; + } + + auto requests = delegate->Requests(); + + // Geolocation permission is not grouped with others. + if (requests.empty() || + requests[0]->request_type() != permissions::RequestType::kGeolocation) { + return; + } + + bool enable_high_accuracy = false; + if (auto* web_contents = delegate->GetAssociatedWebContents()) { + if (auto* geolocation_tab_helper = + BraveGeolocationPermissionTabHelper::FromWebContents( + web_contents)) { + enable_high_accuracy = geolocation_tab_helper->enable_high_accuracy(); + } + } + + geolocation::IsSystemLocationSettingEnabled(base::BindOnce( + [](base::WeakPtr widget_delegate, + base::WeakPtr browser, bool enable_high_accuracy, + bool settings_enabled) { + // Browser or Bubble is already gone. + if (!browser || !widget_delegate) { + return; + } + PermissionPromptBubbleBaseView* bubble_base_view = + static_cast(widget_delegate.get()); + AddGeolocationDescription( + bubble_base_view, browser.get(), + /*enable_high_accuracy*/ enable_high_accuracy, + /*use_exact_location_label*/ settings_enabled); + + // To update widget layout after adding another child view. + bubble_base_view->UpdateAnchorPosition(); + }, + bubble_base_view->AsWeakPtr(), browser->AsWeakPtr(), + enable_high_accuracy)); +} + views::View* AddPermissionLifetimeComboboxIfNeeded( views::BubbleDialogDelegateView* dialog_delegate_view, permissions::PermissionPrompt::Delegate* delegate) { @@ -257,7 +432,8 @@ void AddFootnoteViewIfNeeded( permission_lifetime_view->GetPreferredSize().width()) + \ margins().width()); \ set_should_ignore_snapping(true); \ - } + } \ + AddGeolocationDescriptionIfNeeded(this, delegate_.get(), browser_); #include "src/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc" #undef BRAVE_PERMISSION_PROMPT_BUBBLE_BASE_VIEW diff --git a/chromium_src/third_party/blink/renderer/modules/geolocation/DEPS b/chromium_src/third_party/blink/renderer/modules/geolocation/DEPS new file mode 100644 index 000000000000..992f5164a20c --- /dev/null +++ b/chromium_src/third_party/blink/renderer/modules/geolocation/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+brave/components/brave_geolocation_permission/common", +] diff --git a/chromium_src/third_party/blink/renderer/modules/geolocation/geolocation.cc b/chromium_src/third_party/blink/renderer/modules/geolocation/geolocation.cc new file mode 100644 index 000000000000..dcbbb14b5804 --- /dev/null +++ b/chromium_src/third_party/blink/renderer/modules/geolocation/geolocation.cc @@ -0,0 +1,54 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include "build/build_config.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "services/device/public/mojom/geolocation.mojom-blink.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/frame/local_frame_client.h" + +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#include "brave/components/brave_geolocation_permission/common/brave_geolocation_permission.mojom-blink.h" +#endif + +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +namespace blink { +namespace { + +bool SetEnableHighAccuracy(LocalFrame* frame, bool enable_high_accuracy) { + if (frame->Client()->GetRemoteNavigationAssociatedInterfaces()) { + mojo::AssociatedRemote< + geolocation::mojom::blink::BraveGeolocationPermission> + brave_geolocation_permission_binding; + frame->Client()->GetRemoteNavigationAssociatedInterfaces()->GetInterface( + &brave_geolocation_permission_binding); + CHECK(brave_geolocation_permission_binding.is_bound()); + brave_geolocation_permission_binding->SetEnableHighAccuracy( + enable_high_accuracy); + } + + return enable_high_accuracy; +} + +} // namespace +} // namespace blink + +// Pass enabledHighAccuracy bit to browser to make geolocation permission +// bubble gives more detailed infos. +// Renderer uses |Geolocation| mojo interface and it's used |WebContentsImpl|. +// It means it's in internal content layer impls so hard to get about it from +// client layer. Instead of touching |WebContents|, |Geolocation|, +// |GeolocationContext| interfaces, it would be more simple to pass via +// separated mojo interface. +#define SetHighAccuracy(is_high_accuracy) \ + SetHighAccuracy(SetEnableHighAccuracy(GetFrame(), is_high_accuracy)); +#else +#define SetHighAccuracy(is_high_accuracy) SetHighAccuracy(is_high_accuracy) +#endif + +#include "src/third_party/blink/renderer/modules/geolocation/geolocation.cc" + +#undef SetHighAccuracy diff --git a/components/brave_geolocation_permission/common/BUILD.gn b/components/brave_geolocation_permission/common/BUILD.gn new file mode 100644 index 000000000000..970e54d35bd6 --- /dev/null +++ b/components/brave_geolocation_permission/common/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright (c) 2024 The Brave Authors. All rights reserved. +# 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 https://mozilla.org/MPL/2.0/. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("brave_geolocation_permission") { + sources = [ "brave_geolocation_permission.mojom" ] + + export_class_attribute_blink = "CORE_EXPORT" + export_define_blink = "BLINK_CORE_IMPLEMENTATION=1" + export_header_blink = "third_party/blink/renderer/core/core_export.h" +} diff --git a/components/brave_geolocation_permission/common/brave_geolocation_permission.mojom b/components/brave_geolocation_permission/common/brave_geolocation_permission.mojom new file mode 100644 index 000000000000..7c538bdf7995 --- /dev/null +++ b/components/brave_geolocation_permission/common/brave_geolocation_permission.mojom @@ -0,0 +1,10 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// 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 https://mozilla.org/MPL/2.0/. + +module geolocation.mojom; + +interface BraveGeolocationPermission { + SetEnableHighAccuracy(bool high_accuracy); +}; diff --git a/components/resources/brave_components_strings.grd b/components/resources/brave_components_strings.grd index 9cb58669e64e..3e20582c3353 100644 --- a/components/resources/brave_components_strings.grd +++ b/components/resources/brave_components_strings.grd @@ -797,6 +797,10 @@ You're viewing a WebTorrent page + + Test string for $1place holders$2. $3Learn more$4 + + diff --git a/test/BUILD.gn b/test/BUILD.gn index 85fab137a0af..a40e8f1e4cc4 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -1124,6 +1124,7 @@ test("brave_browser_tests") { "//brave/app/theme:brave_theme_resources_grit", "//brave/app/theme:brave_unscaled_resources_grit", "//brave/browser/sharing_hub:browser_tests", + "//brave/browser/ui/geolocation:browser_tests", "//brave/browser/ui/whats_new:browser_test", "//brave/components/brave_wallet/browser:test_support", "//chrome/browser/apps/app_service:app_service", diff --git a/third_party/blink/renderer/includes.gni b/third_party/blink/renderer/includes.gni index 6778a79eb488..587ead1e4dc1 100644 --- a/third_party/blink/renderer/includes.gni +++ b/third_party/blink/renderer/includes.gni @@ -37,6 +37,10 @@ brave_blink_renderer_core_sources = [ brave_blink_renderer_core_deps = [ "//brave/components/brave_shields/core/common/" ] +if (!is_android && !is_ios) { + brave_blink_renderer_core_deps += [ "//brave/components/brave_geolocation_permission/common:brave_geolocation_permission_blink" ] +} + brave_blink_renderer_core_public_deps += brave_page_graph_core_public_deps brave_blink_renderer_core_sources += brave_page_graph_core_sources brave_blink_renderer_core_deps += brave_page_graph_core_deps