Files
cromite/build/patches/Add-lifetime-options-for-permissions.patch

1448 lines
76 KiB
Diff

From: uazo <uazo@users.noreply.github.com>
Date: Fri, 8 Apr 2022 11:04:04 +0000
Subject: Add lifetime options for permissions
Indicate the session mode for content-settings by using the constraint `content_settings::SessionModel` as
UserSession when setting the value, and also make use of an expiration time value.
This is used in Chromium for `ClientHints` but it is generally possible to use this functionality when a
specific value needs to be persisted by origin.
All content settings of this type are not saved on disk (except for the `Forever` option), allowing user to
reset the status each time application is restarted.
There are 4 main areas affected to introduce the functionality:
* components/content_settings
A new `content_settings::LifetimeMode` enum value is defined to specify the user's
choice (Always, OnlyThisTime, UntilOriginClosed, UntilBrowserClosed).
Enumeration is also generated for java by adding it in `content_settings_enums_javagen` (gn).
This is mainly used in `content_settings_utils.cc` to create a specialised `content_settings::ContentSettingConstraints`
that is then used in `SetContentSettingDefaultScope()` by `PermissionContextBase::UpdateContentSetting`.
Existing Chromium data structures do not provide a specific property to define a choice which is instead encoded through
the `ContentSettingConstraints`; this approach is already used in other parts of the Chromium codebase so it is not
novel here.
Therefore, `content_settings::GetConstraintSessionExpiration()` and `content_settings::IsConstraintSessionExpiration()`
manage the lifetime modes of the session content-settings.
The modification also adds the session pattern to the ContentSettingPatternSource so that it is available for the UI.
* components/permissions
Lifetime support is added to the permissions; most of the changes are caused by the fact that it is necessary to report
the value selected by the user from the Java UI managed by `components/browser_ui` up to
`PermissionContextBase::UpdateContentSetting()`, without necessarily having to modify all requests that are not
related to geolocation/camera/microphone. The approach used is a new
`PermissionRequest::PermissionDecidedCallbackWithLifetime` used by an overload of
`PermissionContextBase::CreatePermissionRequest` so that options are present only for the specific content-settings
(see `PermissionDialogModel.java`).
For other permissions no behaviour is changed (see `PermissionDialogDelegate::Accept`); for geolocation it was
necessary to act directly in the specific context, because, unlike microphone/camera, the content-setting value is
inserted in its specific method (`FinishNotifyPermissionSet`, that calls the callback), even if the class always
derives from `PermissionContextBase`.
* components/page_info
Some changes needed to see in the summary of the `page_info` the text "(only this session)"
(aka `page_info_android_permission_session_permission`) through adding a new property "is_user_session" in
`PageInfoPermissionEntry` (Java).
* components/browser_ui
Changes to the Settings UI to show "(only this session)" in the specific content-setting.
The same view is used both in the settings and in the page_info.
For the management of `UntilOriginClosed` the logic used by flag `kOneTimeGeolocationPermission` was used; this flag
is active only in the desktop (files `last_tab_standing_tracker_*`). It is a class that manages a list of the active
origins and allows to perform operations when all the tabs relating to that origin have been closed, in this case
deleting the session content settings of `UntilOriginClosed`.
See also: https://github.com/bromite/bromite/issues/1549
Original License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html
License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
---
.../permissions/last_tab_standing_tracker.cc | 33 ++++++++
.../one_time_permissions_tracker.cc | 34 +++++++-
.../one_time_permissions_tracker.h | 5 +-
.../one_time_permissions_tracker_factory.cc | 2 +-
.../views/permissions/chip/chip_controller.cc | 2 +-
...exclusive_access_permission_prompt_view.cc | 2 +-
.../permission_prompt_bubble_base_view.cc | 2 +-
.../site_settings/SingleWebsiteSettings.java | 9 ++
.../android/website_preference_bridge.cc | 2 +-
.../strings/android/browser_ui_strings.grd | 5 ++
.../core/browser/content_settings_utils.cc | 44 ++++++++--
.../core/browser/content_settings_utils.h | 6 ++
.../core/common/content_settings_enums.mojom | 9 ++
.../page_info/PageInfoController.java | 4 +-
.../PermissionParamsListBuilder.java | 12 ++-
.../android/page_info_controller_android.cc | 10 ++-
components/page_info/page_info.cc | 2 +
components/page_info/page_info.h | 1 +
.../permissions/PermissionDialogDelegate.java | 13 +++
.../PermissionDialogModelFactory.java | 83 ++++++++++++++++++-
.../embedded_permission_prompt_android.cc | 2 +-
.../embedded_permission_prompt_android.h | 2 +-
.../permission_dialog_delegate.cc | 24 +++++-
.../permission_dialog_delegate.h | 1 +
.../permission_prompt_android.cc | 10 ++-
.../permission_prompt_android.h | 3 +-
.../android/permissions_android_strings.grd | 17 ++++
.../geolocation_permission_context_android.cc | 25 ++++--
.../geolocation_permission_context_android.h | 7 ++
.../embedded_permission_prompt_flow_model.cc | 2 +-
.../permissions/permission_context_base.cc | 58 +++++++++++--
.../permissions/permission_context_base.h | 25 +++++-
components/permissions/permission_prompt.h | 3 +-
components/permissions/permission_request.cc | 43 +++++++++-
components/permissions/permission_request.h | 17 +++-
.../permissions/permission_request_manager.cc | 50 ++++++-----
.../permissions/permission_request_manager.h | 10 ++-
37 files changed, 510 insertions(+), 69 deletions(-)
diff --git a/chrome/browser/permissions/last_tab_standing_tracker.cc b/chrome/browser/permissions/last_tab_standing_tracker.cc
--- a/chrome/browser/permissions/last_tab_standing_tracker.cc
+++ b/chrome/browser/permissions/last_tab_standing_tracker.cc
@@ -7,6 +7,32 @@
#include "base/observer_list.h"
#include "url/gurl.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
+#include "components/permissions/permissions_client.h"
+
+namespace {
+ // Remove all sessions content setting by origin and type
+ void RemoveSessionSettings(HostContentSettingsMap* content_settings,
+ const url::Origin& origin,
+ ContentSettingsType type) {
+ ContentSettingsForOneType session_settings =
+ content_settings->GetSettingsForOneType(
+ type, content_settings::mojom::SessionModel::USER_SESSION);
+
+ GURL url = origin.GetURL();
+ for (ContentSettingPatternSource& entry : session_settings) {
+ if (content_settings::IsConstraintSessionExpiration(entry,
+ content_settings::mojom::LifetimeMode::UNTIL_ORIGIN_CLOSED) &&
+ entry.primary_pattern.Matches(url)) {
+ content_settings->SetWebsiteSettingCustomScope(
+ entry.primary_pattern, entry.secondary_pattern,
+ type, base::Value());
+ }
+ }
+ }
+}
+
LastTabStandingTracker::LastTabStandingTracker(content::BrowserContext* context)
: context_(context) {}
@@ -56,4 +82,11 @@ void LastTabStandingTracker::WebContentsUnloadedOrigin(
for (auto& observer : observer_list_) {
observer.OnLastPageFromOriginClosed(origin);
}
+ HostContentSettingsMap* content_settings =
+ permissions::PermissionsClient::Get()->GetSettingsMap(context_);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::GEOLOCATION);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::GEOLOCATION_WITH_OPTIONS);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::MEDIASTREAM_MIC);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::MEDIASTREAM_CAMERA);
+ }
}
diff --git a/chrome/browser/permissions/one_time_permissions_tracker.cc b/chrome/browser/permissions/one_time_permissions_tracker.cc
--- a/chrome/browser/permissions/one_time_permissions_tracker.cc
+++ b/chrome/browser/permissions/one_time_permissions_tracker.cc
@@ -20,8 +20,34 @@
#include "components/permissions/permission_util.h"
#include "content/public/browser/visibility.h"
#include "url/gurl.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
+#include "components/permissions/permissions_client.h"
+
+namespace {
+ // Remove all sessions content setting by origin and type
+ void RemoveSessionSettings(HostContentSettingsMap* content_settings,
+ const url::Origin& origin,
+ ContentSettingsType type) {
+ ContentSettingsForOneType session_settings =
+ content_settings->GetSettingsForOneType(
+ type, content_settings::mojom::SessionModel::USER_SESSION);
+
+ GURL url = origin.GetURL();
+ for (ContentSettingPatternSource& entry : session_settings) {
+ if (content_settings::IsConstraintSessionExpiration(entry,
+ content_settings::mojom::LifetimeMode::UNTIL_ORIGIN_CLOSED) &&
+ entry.primary_pattern.Matches(url)) {
+ content_settings->SetWebsiteSettingCustomScope(
+ entry.primary_pattern, entry.secondary_pattern,
+ type, base::Value());
+ }
+ }
+ }
+}
-OneTimePermissionsTracker::OneTimePermissionsTracker() = default;
+OneTimePermissionsTracker::OneTimePermissionsTracker(content::BrowserContext* context)
+ : context_(context) {}
OneTimePermissionsTracker::~OneTimePermissionsTracker() = default;
OneTimePermissionsTracker::OriginTrackEntry::OriginTrackEntry() = default;
@@ -260,6 +286,12 @@ void OneTimePermissionsTracker::NotifyLastPageFromOriginClosed(
for (auto& observer : observer_list_) {
observer.OnLastPageFromOriginClosed(origin);
}
+ HostContentSettingsMap* content_settings =
+ permissions::PermissionsClient::Get()->GetSettingsMap(context_);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::GEOLOCATION);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::GEOLOCATION_WITH_OPTIONS);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::MEDIASTREAM_MIC);
+ RemoveSessionSettings(content_settings, origin, ContentSettingsType::MEDIASTREAM_CAMERA);
}
bool OneTimePermissionsTracker::ShouldIgnoreOrigin(const url::Origin& origin) {
diff --git a/chrome/browser/permissions/one_time_permissions_tracker.h b/chrome/browser/permissions/one_time_permissions_tracker.h
--- a/chrome/browser/permissions/one_time_permissions_tracker.h
+++ b/chrome/browser/permissions/one_time_permissions_tracker.h
@@ -13,6 +13,7 @@
#include "base/timer/timer.h"
#include "chrome/browser/permissions/one_time_permissions_tracker_observer.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "chrome/browser/profiles/profile.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/visibility.h"
@@ -27,7 +28,7 @@ class OneTimePermissionsTracker : public KeyedService {
void (OneTimePermissionsTracker::*)(const url::Origin&);
public:
- OneTimePermissionsTracker();
+ OneTimePermissionsTracker(content::BrowserContext* context);
~OneTimePermissionsTracker() override;
OneTimePermissionsTracker(const OneTimePermissionsTracker&) = delete;
@@ -148,7 +149,7 @@ class OneTimePermissionsTracker : public KeyedService {
base::ObserverList<OneTimePermissionsTrackerObserver> observer_list_;
std::map<url::Origin, OriginTrackEntry> origin_tracker_;
-
+ raw_ptr<content::BrowserContext> context_;
base::WeakPtrFactory<OneTimePermissionsTracker> weak_factory_{this};
};
diff --git a/chrome/browser/permissions/one_time_permissions_tracker_factory.cc b/chrome/browser/permissions/one_time_permissions_tracker_factory.cc
--- a/chrome/browser/permissions/one_time_permissions_tracker_factory.cc
+++ b/chrome/browser/permissions/one_time_permissions_tracker_factory.cc
@@ -44,5 +44,5 @@ bool OneTimePermissionsTrackerFactory::ServiceIsCreatedWithBrowserContext()
std::unique_ptr<KeyedService>
OneTimePermissionsTrackerFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
- return std::make_unique<OneTimePermissionsTracker>();
+ return std::make_unique<OneTimePermissionsTracker>(context);
}
diff --git a/chrome/browser/ui/views/permissions/chip/chip_controller.cc b/chrome/browser/ui/views/permissions/chip/chip_controller.cc
--- a/chrome/browser/ui/views/permissions/chip/chip_controller.cc
+++ b/chrome/browser/ui/views/permissions/chip/chip_controller.cc
@@ -235,7 +235,7 @@ void ChipController::OnWidgetDestroyed(views::Widget* widget) {
break;
case permissions::PermissionAction::GRANTED_ONCE:
active_chip_permission_request_manager_.value()->AcceptThisTime(
- /*prompt_options=*/std::monostate());
+ /*prompt_options=*/std::monostate(), content_settings::mojom::LifetimeMode::ONLY_THIS_TIME);
break;
case permissions::PermissionAction::DENIED:
active_chip_permission_request_manager_.value()->Deny(
diff --git a/chrome/browser/ui/views/permissions/exclusive_access_permission_prompt_view.cc b/chrome/browser/ui/views/permissions/exclusive_access_permission_prompt_view.cc
--- a/chrome/browser/ui/views/permissions/exclusive_access_permission_prompt_view.cc
+++ b/chrome/browser/ui/views/permissions/exclusive_access_permission_prompt_view.cc
@@ -118,7 +118,7 @@ void ExclusiveAccessPermissionPromptView::RunButtonCallback(int button_id) {
request_type(), GetPermissionActionString(button),
record_browser_always_active_value());
if (button == ButtonType::kAllowThisTime) {
- delegate_->AcceptThisTime(/*prompt_options=*/std::monostate());
+ delegate_->AcceptThisTime(/*prompt_options=*/std::monostate(), content_settings::mojom::LifetimeMode::ONLY_THIS_TIME);
} else if (button == ButtonType::kAlwaysAllow) {
delegate_->Accept(/*prompt_options=*/std::monostate());
} else if (button == ButtonType::kNeverAllow) {
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
--- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
+++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc
@@ -321,7 +321,7 @@ void PermissionPromptBubbleBaseView::RunButtonCallback(int button_id) {
delegate_->Accept(/*prompt_options=*/std::monostate());
return;
case PermissionDialogButton::kAcceptOnce:
- delegate_->AcceptThisTime(/*prompt_options=*/std::monostate());
+ delegate_->AcceptThisTime(/*prompt_options=*/std::monostate(), content_settings::mojom::LifetimeMode::ONLY_THIS_TIME);
return;
case PermissionDialogButton::kDeny:
#if BUILDFLAG(IS_CHROMEOS)
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -724,6 +724,11 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment
}
@RequiresNonNull({"mSite"})
+ private boolean isSessionPermission(@ContentSettingsType.EnumType int type) {
+ return mSite.getPermissionInfo(type) != null &&
+ mSite.getPermissionInfo(type).getSessionModel() == SessionModel.USER_SESSION;
+ }
+
private void setUpClearDataPreference() {
ClearWebsiteStorage preference = findPreference(PREF_CLEAR_DATA);
long usage = mSite.getTotalUsage();
@@ -1404,6 +1409,10 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment
.getDefaultColor());
}
}
+ if (preference instanceof ChromeSwitchPreference && isSessionPermission(contentType)) {
+ ((ChromeSwitchPreference)preference).setSummary(preference.getSummary() + " " +
+ getString(R.string.page_info_android_permission_session_permission));
+ }
}
/**
diff --git a/components/browser_ui/site_settings/android/website_preference_bridge.cc b/components/browser_ui/site_settings/android/website_preference_bridge.cc
--- a/components/browser_ui/site_settings/android/website_preference_bridge.cc
+++ b/components/browser_ui/site_settings/android/website_preference_bridge.cc
@@ -238,7 +238,7 @@ void GetOrigins(JNIEnv* env,
seen_origins.push_back(origin);
insertionFunc(env, static_cast<int>(content_type), list,
ConvertOriginToJavaString(env, origin), jembedder,
- /*is_embargoed=*/true, /*is_one_time=*/false);
+ /*is_embargoed=*/true, 0);
}
}
}
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd
--- a/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -629,6 +629,11 @@
<message name="IDS_PAGE_INFO_URL_TRUNCATED" desc="Accessibility announcement when the URL in PageInfo switches from full to truncated display">
URL truncated
</message>
+ <message name="IDS_PAGE_INFO_ANDROID_PERMISSION_SESSION_PERMISSION"
+ desc="The label used in the About Page dialog to indicate a session permission">
+ (only this session)
+ </message>
+
<message name="IDS_PAGE_INFO_AD_PRIVACY_HEADER" desc="A label that represents the new ad-related settings. 1) Navigate to any site. 2) Click the icon (often a lock) to the left of the URL in the address bar. Information about the page you're viewing appears. The 'Ad privacy' label will appear above the 'Site settings' button.">
Ad privacy
</message>
diff --git a/components/content_settings/core/browser/content_settings_utils.cc b/components/content_settings/core/browser/content_settings_utils.cc
--- a/components/content_settings/core/browser/content_settings_utils.cc
+++ b/components/content_settings/core/browser/content_settings_utils.cc
@@ -182,6 +182,42 @@ bool IsConstraintPersistent(const ContentSettingConstraints& constraints) {
return constraints.session_model() == mojom::SessionModel::DURABLE;
}
+ContentSettingConstraints GetConstraintSessionExpiration(content_settings::mojom::LifetimeMode lifetime_mode) {
+ int lifetime;
+ base::Time now;
+ if (lifetime_mode == content_settings::mojom::LifetimeMode::ONLY_THIS_TIME) {
+ // note: this content settings will be discarded immediately
+ // 1h is used as a magic constant to identify the one-time lifetime mode
+ lifetime = 1;
+ } else if (lifetime_mode == content_settings::mojom::LifetimeMode::UNTIL_ORIGIN_CLOSED) {
+ now = base::Time::Now();
+ lifetime = 24;
+ } else {
+ lifetime = 0;
+ }
+ ContentSettingConstraints c(now);
+ c.set_lifetime(base::Hours(lifetime));
+ c.set_session_model(mojom::SessionModel::USER_SESSION);
+ return c;
+}
+
+bool IsConstraintSessionExpiration(const ContentSettingPatternSource& source,
+ content_settings::mojom::LifetimeMode lifetime_mode) {
+ if (source.metadata.session_model() != content_settings::mojom::SessionModel::USER_SESSION)
+ return false;
+
+ mojom::LifetimeMode type;
+ if (source.metadata.lifetime() == base::Hours(24)) {
+ type = content_settings::mojom::LifetimeMode::UNTIL_ORIGIN_CLOSED;
+ } else if (source.metadata.expiration() == (base::Time() + base::Hours(1))) {
+ type = content_settings::mojom::LifetimeMode::ONLY_THIS_TIME;
+ } else {
+ type = content_settings::mojom::LifetimeMode::UNTIL_BROWSER_CLOSED;
+ }
+
+ return lifetime_mode == type;
+}
+
bool CanTrackLastVisit(ContentSettingsType type) {
DCHECK(WebsiteSettingsRegistry::GetInstance()->Get(type)) << type;
@@ -267,10 +303,6 @@ const std::vector<ContentSettingsType>& GetTypesWithTemporaryGrants() {
ContentSettingsType::CAPTURED_SURFACE_CONTROL,
#endif
ContentSettingsType::KEYBOARD_LOCK,
- ContentSettingsType::GEOLOCATION,
- ContentSettingsType::GEOLOCATION_WITH_OPTIONS,
- ContentSettingsType::MEDIASTREAM_MIC,
- ContentSettingsType::MEDIASTREAM_CAMERA,
ContentSettingsType::SENSORS,
ContentSettingsType::HAND_TRACKING,
ContentSettingsType::SMART_CARD_DATA,
@@ -287,10 +319,6 @@ const std::vector<ContentSettingsType>& GetTypesWithTemporaryGrantsInHcsm() {
ContentSettingsType::CAPTURED_SURFACE_CONTROL,
#endif
ContentSettingsType::KEYBOARD_LOCK,
- ContentSettingsType::GEOLOCATION,
- ContentSettingsType::GEOLOCATION_WITH_OPTIONS,
- ContentSettingsType::MEDIASTREAM_MIC,
- ContentSettingsType::MEDIASTREAM_CAMERA,
ContentSettingsType::SENSORS,
ContentSettingsType::HAND_TRACKING,
ContentSettingsType::AR,
diff --git a/components/content_settings/core/browser/content_settings_utils.h b/components/content_settings/core/browser/content_settings_utils.h
--- a/components/content_settings/core/browser/content_settings_utils.h
+++ b/components/content_settings/core/browser/content_settings_utils.h
@@ -78,6 +78,12 @@ bool IsConstraintPersistent(const ContentSettingConstraints& constraints);
// Returns whether the given type supports tracking last_visit timestamps.
bool CanTrackLastVisit(ContentSettingsType type);
+ContentSettingConstraints GetConstraintSessionExpiration(mojom::LifetimeMode lifetime_mode);
+
+bool IsConstraintSessionExpiration(
+ const ContentSettingPatternSource& source,
+ mojom::LifetimeMode lifetime_mode);
+
// Get a timestamp with week-precision.
base::Time GetCoarseVisitedTime(base::Time time);
diff --git a/components/content_settings/core/common/content_settings_enums.mojom b/components/content_settings/core/common/content_settings_enums.mojom
--- a/components/content_settings/core/common/content_settings_enums.mojom
+++ b/components/content_settings/core/common/content_settings_enums.mojom
@@ -63,6 +63,15 @@ enum SessionModel {
ONE_TIME = 3,
};
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.content_settings
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: LifetimeMode
+enum LifetimeMode {
+ ALWAYS = 99,
+ ONLY_THIS_TIME = 1,
+ UNTIL_ORIGIN_CLOSED = 2,
+ UNTIL_BROWSER_CLOSED = 0,
+};
+
// Identifies the content settings provider of a content setting.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.content_settings
// GENERATED_JAVA_CLASS_NAME_OVERRIDE: ProviderType
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
@@ -384,9 +384,9 @@ public class PageInfoController
*/
@CalledByNative
private void addPermissionSection(
- String name, String nameMidSentence, int type, boolean allowed, boolean requested) {
+ String name, String nameMidSentence, int type, boolean allowed, boolean requested, boolean is_user_session) {
mPermissionParamsListBuilder.addPermissionEntry(
- name, nameMidSentence, type, allowed, requested);
+ name, nameMidSentence, type, allowed, requested, is_user_session);
}
/** Update the permissions view based on the contents of mDisplayedPermissions. */
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java b/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java
@@ -47,8 +47,8 @@ public class PermissionParamsListBuilder {
}
public void addPermissionEntry(
- String name, String nameMidSentence, int type, boolean allowed, boolean requested) {
- mEntries.add(new PageInfoPermissionEntry(name, nameMidSentence, type, allowed, requested));
+ String name, String nameMidSentence, int type, boolean allowed, boolean requested, boolean is_user_session) {
+ mEntries.add(new PageInfoPermissionEntry(name, nameMidSentence, type, allowed, requested, is_user_session));
}
public void clearPermissionEntries() {
@@ -85,6 +85,10 @@ public class PermissionParamsListBuilder {
} else {
warningTextResource = R.string.page_info_android_permission_blocked;
}
+ if (permission.is_user_session) {
+ warningTextResource =
+ R.string.page_info_android_permission_session_permission;
+ }
}
}
@@ -115,14 +119,16 @@ public class PermissionParamsListBuilder {
public final int type;
public final boolean allowed;
public final boolean requested;
+ public final boolean is_user_session;
PageInfoPermissionEntry(
- String name, String nameMidSentence, int type, boolean allowed, boolean requested) {
+ String name, String nameMidSentence, int type, boolean allowed, boolean requested, boolean is_user_session) {
this.name = name;
this.nameMidSentence = nameMidSentence;
this.type = type;
this.allowed = allowed;
this.requested = requested;
+ this.is_user_session = is_user_session;
}
@Override
diff --git a/components/page_info/android/page_info_controller_android.cc b/components/page_info/android/page_info_controller_android.cc
--- a/components/page_info/android/page_info_controller_android.cc
+++ b/components/page_info/android/page_info_controller_android.cc
@@ -219,6 +219,8 @@ void PageInfoControllerAndroid::SetPermissionInfo(
// being requested. This is needed for the Clapper experiment
// (crbug.com/458351800) and (crbug.com/463333225).
bool requested_notifications = false;
+ std::map<ContentSettingsType, bool>
+ user_specified_settings_is_user_session;
for (const auto& permission : permission_info_list) {
if (std::ranges::contains(permissions_to_display, permission.type)) {
@@ -231,6 +233,8 @@ void PageInfoControllerAndroid::SetPermissionInfo(
user_specified_settings_to_display[permission.type] =
info->delegate().IsAnyPermissionAllowed(*setting_to_display);
+ user_specified_settings_is_user_session[permission.type] =
+ permission.is_user_session;
}
// Notifications permission can have the setting to display as DEFAULT
@@ -257,7 +261,8 @@ void PageInfoControllerAndroid::SetPermissionInfo(
ConvertUTF16ToJavaString(env, setting_title_mid_sentence),
static_cast<int32_t>(permission),
user_specified_settings_to_display[permission],
- requested_notifications);
+ requested_notifications,
+ user_specified_settings_is_user_session[permission]);
}
}
@@ -270,7 +275,8 @@ void PageInfoControllerAndroid::SetPermissionInfo(
env, controller_jobject_, ConvertUTF16ToJavaString(env, object_title),
ConvertUTF16ToJavaString(env, object_title),
static_cast<int32_t>(chosen_object->ui_info->content_settings_type),
- static_cast<int32_t>(CONTENT_SETTING_ALLOW), requested_notifications);
+ static_cast<int32_t>(CONTENT_SETTING_ALLOW), requested_notifications,
+ /* is_user_session */ false);
}
Java_PageInfoController_updatePermissionDisplay(env, controller_jobject_);
diff --git a/components/page_info/page_info.cc b/components/page_info/page_info.cc
--- a/components/page_info/page_info.cc
+++ b/components/page_info/page_info.cc
@@ -1314,6 +1314,8 @@ void PageInfo::PopulatePermissionInfo(PermissionInfo& permission_info,
permission_info.is_one_time =
(info.metadata.session_model() ==
content_settings::mojom::SessionModel::ONE_TIME);
+ permission_info.is_user_session =
+ (info.metadata.session_model() == content_settings::mojom::SessionModel::USER_SESSION);
auto* setting_info =
content_settings::PermissionSettingsRegistry::GetInstance()->Get(
diff --git a/components/page_info/page_info.h b/components/page_info/page_info.h
--- a/components/page_info/page_info.h
+++ b/components/page_info/page_info.h
@@ -150,6 +150,7 @@ class PageInfo : private content_settings::CookieControlsObserver,
content_settings::SettingSource::kNone;
// Whether the permission is a one-time grant.
bool is_one_time = false;
+ bool is_user_session = false;
// Only set for settings that can have multiple permissions for different
// embedded origins.
std::optional<url::Origin> requesting_origin;
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogDelegate.java b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogDelegate.java
--- a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogDelegate.java
+++ b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogDelegate.java
@@ -17,6 +17,7 @@ import org.chromium.build.annotations.NullMarked;
import org.chromium.build.annotations.Nullable;
import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.base.WindowAndroid;
+import org.chromium.components.content_settings.LifetimeMode;
import java.util.ArrayList;
import java.util.List;
@@ -68,6 +69,9 @@ public class PermissionDialogDelegate {
// Prompt(screen) variant we want to display on the dialog.
private @EmbeddedPromptVariant int mEmbeddedPromptVariant;
+ /** Lifetime option selected by the user. */
+ private int mSelectedLifetimeOption = LifetimeMode.ALWAYS;
+
/**
* Defines a (potentially empty) list of ranges represented as pairs of <startIndex, endIndex>,
* which shall be used by the UI to format the specified ranges as bold text.
@@ -145,6 +149,15 @@ public class PermissionDialogDelegate {
PermissionDialogDelegateJni.get().acceptThisTime(mNativeDelegatePtr);
}
+ public void setSelectedLifetimeOption(int idx) {
+ mSelectedLifetimeOption = idx;
+ }
+
+ @CalledByNative
+ public int getSelectedLifetimeOption() {
+ return mSelectedLifetimeOption;
+ }
+
public void onDeny() {
assert mNativeDelegatePtr != 0;
PermissionDialogDelegateJni.get().deny(mNativeDelegatePtr);
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogModelFactory.java b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogModelFactory.java
--- a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogModelFactory.java
+++ b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogModelFactory.java
@@ -14,6 +14,18 @@ import org.chromium.ui.UiUtils;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;
+import java.util.Arrays;
+import java.util.List;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.TextView;
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.ui.base.ViewUtils;
+import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.components.content_settings.LifetimeMode;
+
/** This class creates the model for the permission dialog. */
@NullMarked
class PermissionDialogModelFactory {
@@ -77,7 +89,76 @@ class PermissionDialogModelFactory {
ModalDialogProperties.ButtonStyles.PRIMARY_FILLED_NEGATIVE_OUTLINE)
.with(ModalDialogProperties.CHANGE_CUSTOM_VIEW_OR_BUTTONS, true);
}
- return builder.build();
+
+ PropertyModel pm = builder.build();
+ int[] types = delegate.getContentSettingsTypes();
+ if (contains(types, ContentSettingsType.GEOLOCATION) ||
+ contains(types, ContentSettingsType.GEOLOCATION_WITH_OPTIONS) ||
+ contains(types, ContentSettingsType.MEDIASTREAM_MIC) ||
+ contains(types, ContentSettingsType.MEDIASTREAM_CAMERA))
+ {
+ LinearLayout layout = (LinearLayout) customView;
+
+ // Create a text label before the lifetime selector.
+ TextView lifetimeOptionsText = new TextView(context);
+ lifetimeOptionsText.setText(context.getString(
+ org.chromium.components.permissions.R.string.session_permissions_title));
+ lifetimeOptionsText.setTextAppearance(
+ lifetimeOptionsText.getContext(), R.style.TextAppearance_TextMedium_Primary);
+
+ LinearLayout.LayoutParams lifetimeOptionsTextLayoutParams =
+ new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ lifetimeOptionsTextLayoutParams.setMargins(0, 0, 0, ViewUtils.dpToPx(context, 8));
+ lifetimeOptionsText.setLayoutParams(lifetimeOptionsTextLayoutParams);
+ layout.addView(lifetimeOptionsText);
+
+ // Create radio buttons with lifetime options.
+ RadioGroup radioGroup = new RadioGroup(context);
+
+ RadioButton radioButton = new RadioButton(context);
+ radioButton.setText(context.getString(
+ org.chromium.components.permissions.R.string.session_permissions_only_this_this));
+ radioButton.setId(LifetimeMode.ONLY_THIS_TIME);
+ radioGroup.addView(radioButton);
+
+ radioButton = new RadioButton(context);
+ radioButton.setText(context.getString(
+ org.chromium.components.permissions.R.string.session_permissions_until_page_close));
+ radioButton.setId(LifetimeMode.UNTIL_ORIGIN_CLOSED);
+ radioGroup.addView(radioButton);
+
+ radioButton = new RadioButton(context);
+ radioButton.setText(context.getString(
+ org.chromium.components.permissions.R.string.session_permissions_until_browser_close));
+ radioButton.setId(LifetimeMode.UNTIL_BROWSER_CLOSED);
+ radioGroup.addView(radioButton);
+
+ radioButton = new RadioButton(context);
+ radioButton.setText(context.getString(
+ org.chromium.components.permissions.R.string.session_permissions_forever));
+ radioButton.setId(LifetimeMode.ALWAYS);
+ radioGroup.addView(radioButton);
+
+ radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ delegate.setSelectedLifetimeOption(checkedId);
+ }
+ });
+ radioGroup.check(1);
+ layout.addView(radioGroup);
+ }
+
+ return pm;
+ }
+
+ private static boolean contains(final int[] array, final int key) {
+ int length = array.length;
+ for(int i = 0; i < length; i++) {
+ if (array[i] == key)
+ return true;
+ }
+ return false;
}
public static ModalDialogProperties.ModalDialogButtonSpec[] getButtonSpecs(
diff --git a/components/permissions/android/permission_prompt/embedded_permission_prompt_android.cc b/components/permissions/android/permission_prompt/embedded_permission_prompt_android.cc
--- a/components/permissions/android/permission_prompt/embedded_permission_prompt_android.cc
+++ b/components/permissions/android/permission_prompt/embedded_permission_prompt_android.cc
@@ -126,7 +126,7 @@ void EmbeddedPermissionPromptAndroid::Acknowledge(
}
void EmbeddedPermissionPromptAndroid::AcceptThisTime(
- const PromptOptions& prompt_options) {
+ const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetimeOption) {
prompt_model_->PrecalculateVariantsForMetrics();
prompt_model_->RecordPermissionActionUKM(
permissions::ElementAnchoredBubbleAction::kGrantedOnce);
diff --git a/components/permissions/android/permission_prompt/embedded_permission_prompt_android.h b/components/permissions/android/permission_prompt/embedded_permission_prompt_android.h
--- a/components/permissions/android/permission_prompt/embedded_permission_prompt_android.h
+++ b/components/permissions/android/permission_prompt/embedded_permission_prompt_android.h
@@ -45,7 +45,7 @@ class EmbeddedPermissionPromptAndroid : public PermissionPromptAndroid {
const override;
void Dismiss(const PromptOptions& prompt_options) override;
void Accept(const PromptOptions& prompt_options) override;
- void AcceptThisTime(const PromptOptions& prompt_options) override;
+ void AcceptThisTime(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetimeOption) override;
void Acknowledge(const PromptOptions& prompt_options) override;
void Deny(const PromptOptions& prompt_options) override;
void Resumed() override;
diff --git a/components/permissions/android/permission_prompt/permission_dialog_delegate.cc b/components/permissions/android/permission_prompt/permission_dialog_delegate.cc
--- a/components/permissions/android/permission_prompt/permission_dialog_delegate.cc
+++ b/components/permissions/android/permission_prompt/permission_dialog_delegate.cc
@@ -136,6 +136,11 @@ void PermissionDialogJavaDelegate::UpdateDialog() {
static_cast<int>(permission_prompt_->GetEmbeddedPromptVariant()));
}
+int PermissionDialogJavaDelegate::GetSelectedLifetimeOption() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_PermissionDialogDelegate_getSelectedLifetimeOption(env, j_delegate_);
+}
+
// static
std::unique_ptr<PermissionDialogDelegate> PermissionDialogDelegate::Create(
content::WebContents* web_contents,
@@ -164,12 +169,22 @@ PermissionDialogDelegate::CreateForTesting(
void PermissionDialogDelegate::Accept(JNIEnv* env) {
CHECK(permission_prompt_);
+ content_settings::mojom::LifetimeMode lifetimeOption =
+ static_cast<content_settings::mojom::LifetimeMode>(
+ java_delegate_->GetSelectedLifetimeOption());
+ if (lifetimeOption != content_settings::mojom::LifetimeMode::ALWAYS) {
+ permission_prompt_->AcceptThisTime(prompt_options_, lifetimeOption);
+ return;
+ }
permission_prompt_->Accept(prompt_options_);
}
void PermissionDialogDelegate::AcceptThisTime(JNIEnv* env) {
CHECK(permission_prompt_);
- permission_prompt_->AcceptThisTime(prompt_options_);
+ content_settings::mojom::LifetimeMode lifetimeOption =
+ static_cast<content_settings::mojom::LifetimeMode>(
+ java_delegate_->GetSelectedLifetimeOption());
+ permission_prompt_->AcceptThisTime(prompt_options_, lifetimeOption);
}
void PermissionDialogDelegate::Acknowledge(JNIEnv* env) {
@@ -179,6 +194,13 @@ void PermissionDialogDelegate::Acknowledge(JNIEnv* env) {
void PermissionDialogDelegate::Deny(JNIEnv* env) {
CHECK(permission_prompt_);
+ content_settings::mojom::LifetimeMode lifetimeOption =
+ static_cast<content_settings::mojom::LifetimeMode>(
+ java_delegate_->GetSelectedLifetimeOption());
+ if (lifetimeOption != content_settings::mojom::LifetimeMode::ALWAYS) {
+ permission_prompt_->DenyThisTime(prompt_options_, lifetimeOption);
+ return;
+ }
permission_prompt_->Deny(prompt_options_);
}
diff --git a/components/permissions/android/permission_prompt/permission_dialog_delegate.h b/components/permissions/android/permission_prompt/permission_dialog_delegate.h
--- a/components/permissions/android/permission_prompt/permission_dialog_delegate.h
+++ b/components/permissions/android/permission_prompt/permission_dialog_delegate.h
@@ -46,6 +46,7 @@ class PermissionDialogJavaDelegate {
const favicon_base::FaviconRawBitmapResult& favicon_result);
virtual void DismissDialog();
+ virtual int GetSelectedLifetimeOption();
virtual void UpdateDialog();
diff --git a/components/permissions/android/permission_prompt/permission_prompt_android.cc b/components/permissions/android/permission_prompt/permission_prompt_android.cc
--- a/components/permissions/android/permission_prompt/permission_prompt_android.cc
+++ b/components/permissions/android/permission_prompt/permission_prompt_android.cc
@@ -86,14 +86,20 @@ void PermissionPromptAndroid::Accept(const PromptOptions& prompt_options) {
}
void PermissionPromptAndroid::AcceptThisTime(
- const PromptOptions& prompt_options) {
- delegate_->AcceptThisTime(prompt_options);
+ const PromptOptions& prompt_options,
+ content_settings::mojom::LifetimeMode lifetimeOption) {
+ delegate_->AcceptThisTime(prompt_options, lifetimeOption);
}
void PermissionPromptAndroid::Deny(const PromptOptions& prompt_options) {
delegate_->Deny(prompt_options);
}
+void PermissionPromptAndroid::DenyThisTime(const PromptOptions& prompt_options,
+ content_settings::mojom::LifetimeMode lifetimeOption) {
+ delegate_->DenyThisTime(prompt_options, lifetimeOption);
+}
+
void PermissionPromptAndroid::Ignore(const PromptOptions& prompt_options) {
delegate_->Ignore(prompt_options);
}
diff --git a/components/permissions/android/permission_prompt/permission_prompt_android.h b/components/permissions/android/permission_prompt/permission_prompt_android.h
--- a/components/permissions/android/permission_prompt/permission_prompt_android.h
+++ b/components/permissions/android/permission_prompt/permission_prompt_android.h
@@ -57,10 +57,11 @@ class PermissionPromptAndroid : public PermissionPrompt {
const;
virtual void Dismiss(const PromptOptions& prompt_options);
virtual void Accept(const PromptOptions& prompt_options);
- virtual void AcceptThisTime(const PromptOptions& prompt_options);
+ virtual void AcceptThisTime(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetimeOption);
virtual void Acknowledge(const PromptOptions& prompt_options) {}
virtual void Deny(const PromptOptions& prompt_options);
virtual void Ignore(const PromptOptions& prompt_options);
+ virtual void DenyThisTime(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetimeOption);
virtual void Resumed() {}
virtual void SystemSettingsShown() {}
virtual void SystemPermissionResolved(bool accepted) {}
diff --git a/components/permissions/android/permissions_android_strings.grd b/components/permissions/android/permissions_android_strings.grd
--- a/components/permissions/android/permissions_android_strings.grd
+++ b/components/permissions/android/permissions_android_strings.grd
@@ -272,6 +272,23 @@
Unknown or unsupported device (<ph name="DEVICE_ID">%1$s<ex>A1:B2:C3:D4:E5:F6</ex></ph>)
</message>
+ <!-- Session permissions -->
+ <message name="IDS_SESSION_PERMISSIONS_TITLE" desc="Title for the session section in the permission request">
+ Remember my decision
+ </message>
+ <message name="IDS_SESSION_PERMISSIONS_ONLY_THIS_THIS" desc="Message indicating that the permission is only for this time">
+ Only this time
+ </message>
+ <message name="IDS_SESSION_PERMISSIONS_UNTIL_PAGE_CLOSE" desc="Message indicating that the permission is deleted after navigating away from the page">
+ Until all pages of this origin are closed
+ </message>
+ <message name="IDS_SESSION_PERMISSIONS_UNTIL_BROWSER_CLOSE" desc="Message indicating that the permission is for the session only">
+ Until Bromite is closed
+ </message>
+ <message name="IDS_SESSION_PERMISSIONS_FOREVER" desc="Message indicating that the permission is for all sessions">
+ Forever
+ </message>
+
<!-- Item Chooser UI strings -->
<message name="IDS_ITEM_CHOOSER_ITEM_NAME_WITH_ID" desc="To distinguish items with the same name, the item chooser shows the item name with id.">
<ph name="ITEM_NAME">%1$s<ex>item_name</ex></ph> (<ph name="ITEM_ID">%2$s<ex>item id</ex></ph>)
diff --git a/components/permissions/contexts/geolocation_permission_context_android.cc b/components/permissions/contexts/geolocation_permission_context_android.cc
--- a/components/permissions/contexts/geolocation_permission_context_android.cc
+++ b/components/permissions/contexts/geolocation_permission_context_android.cc
@@ -213,7 +213,17 @@ void GeolocationPermissionContextAndroid::NotifyPermissionSet(
bool persist,
const permissions::PermissionPromptDecision& decision) {
DCHECK(decision.is_final);
+ NotifyPermissionSetWithLifetime(request_data,
+ std::move(callback), persist, decision,
+ content_settings::mojom::LifetimeMode::ALWAYS);
+}
+void GeolocationPermissionContextAndroid::NotifyPermissionSetWithLifetime(
+ const PermissionRequestData& request_data,
+ BrowserPermissionCallback callback,
+ bool persist,
+ const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option) {
bool is_default_search =
IsRequestingOriginDSE(request_data.requesting_origin);
if (decision.overall_decision == PermissionDecision::kAllow &&
@@ -233,6 +243,7 @@ void GeolocationPermissionContextAndroid::NotifyPermissionSet(
.overall_decision = PermissionDecision::kDeny,
.prompt_options = decision.prompt_options,
.is_final = true},
+ lifetime_option,
request_data.embedded_permission_request_descriptor.Clone());
return;
}
@@ -258,6 +269,7 @@ void GeolocationPermissionContextAndroid::NotifyPermissionSet(
.overall_decision = PermissionDecision::kDeny,
.prompt_options = decision.prompt_options,
.is_final = true},
+ lifetime_option,
request_data.embedded_permission_request_descriptor.Clone());
return;
}
@@ -270,13 +282,13 @@ void GeolocationPermissionContextAndroid::NotifyPermissionSet(
base::BindOnce(
&GeolocationPermissionContextAndroid::OnLocationSettingsDialogShown,
weak_factory_.GetWeakPtr(), request_data.requesting_origin,
- request_data.embedding_origin, persist, decision));
+ request_data.embedding_origin, persist, decision, lifetime_option));
return;
}
FinishNotifyPermissionSet(
request_data.id, request_data.requesting_origin,
- request_data.embedding_origin, std::move(callback), persist, decision,
+ request_data.embedding_origin, std::move(callback), persist, decision, lifetime_option,
request_data.embedded_permission_request_descriptor.Clone());
}
@@ -459,6 +471,7 @@ void GeolocationPermissionContextAndroid::OnLocationSettingsDialogShown(
const GURL& embedding_origin,
bool persist,
const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option,
LocationSettingsDialogOutcome prompt_outcome) {
bool is_default_search = IsRequestingOriginDSE(requesting_origin);
PermissionPromptDecision result_decision = decision;
@@ -477,7 +490,7 @@ void GeolocationPermissionContextAndroid::OnLocationSettingsDialogShown(
FinishNotifyPermissionSet(
location_settings_dialog_request_id_, requesting_origin, embedding_origin,
- std::move(location_settings_dialog_callback_), persist, result_decision);
+ std::move(location_settings_dialog_callback_), persist, result_decision, lifetime_option);
location_settings_dialog_request_id_ =
PermissionRequestID(content::GlobalRenderFrameHostId(0, 0),
@@ -491,6 +504,7 @@ void GeolocationPermissionContextAndroid::FinishNotifyPermissionSet(
BrowserPermissionCallback callback,
bool persist,
const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option,
blink::mojom::EmbeddedPermissionRequestDescriptorPtr
embedded_permission_request_descriptor) {
PermissionRequestData request_data(
@@ -502,8 +516,9 @@ void GeolocationPermissionContextAndroid::FinishNotifyPermissionSet(
requesting_origin, embedding_origin);
request_data.embedded_permission_request_descriptor =
std::move(embedded_permission_request_descriptor);
- GeolocationPermissionContext::NotifyPermissionSet(
- request_data, std::move(callback), persist, decision);
+ GeolocationPermissionContext::NotifyPermissionSetImpl(
+ request_data, std::move(callback), persist, decision,
+ /*use_lifetime_option*/ true, lifetime_option);
}
void GeolocationPermissionContextAndroid::SetLocationSettingsForTesting(
diff --git a/components/permissions/contexts/geolocation_permission_context_android.h b/components/permissions/contexts/geolocation_permission_context_android.h
--- a/components/permissions/contexts/geolocation_permission_context_android.h
+++ b/components/permissions/contexts/geolocation_permission_context_android.h
@@ -98,6 +98,11 @@ class GeolocationPermissionContextAndroid
BrowserPermissionCallback callback,
bool persist,
const permissions::PermissionPromptDecision& decision) override;
+ void NotifyPermissionSetWithLifetime(const PermissionRequestData& request_data,
+ BrowserPermissionCallback callback,
+ bool persist,
+ const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option) override;
content::PermissionResult UpdatePermissionStatusWithDeviceStatus(
content::WebContents* web_contents,
content::PermissionResult result,
@@ -143,6 +148,7 @@ class GeolocationPermissionContextAndroid
const GURL& embedding_origin,
bool persist,
const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option,
LocationSettingsDialogOutcome prompt_outcome);
void FinishNotifyPermissionSet(
@@ -152,6 +158,7 @@ class GeolocationPermissionContextAndroid
BrowserPermissionCallback callback,
bool persist,
const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option,
blink::mojom::EmbeddedPermissionRequestDescriptorPtr
embedded_permission_request_descriptor = nullptr);
diff --git a/components/permissions/embedded_permission_prompt_flow_model.cc b/components/permissions/embedded_permission_prompt_flow_model.cc
--- a/components/permissions/embedded_permission_prompt_flow_model.cc
+++ b/components/permissions/embedded_permission_prompt_flow_model.cc
@@ -297,7 +297,7 @@ void EmbeddedPermissionPromptFlowModel::SetDelegateAction(
delegate_->Accept(prompt_options);
break;
case DelegateAction::kAllowThisTime:
- delegate_->AcceptThisTime(prompt_options);
+ delegate_->AcceptThisTime(prompt_options, content_settings::mojom::LifetimeMode::ONLY_THIS_TIME);
break;
case DelegateAction::kDeny:
delegate_->Deny(prompt_options);
diff --git a/components/permissions/permission_context_base.cc b/components/permissions/permission_context_base.cc
--- a/components/permissions/permission_context_base.cc
+++ b/components/permissions/permission_context_base.cc
@@ -321,6 +321,17 @@ PermissionContextBase::CreatePermissionRequest(
std::move(request_finished_callback), UsesAutomaticEmbargo());
}
+std::unique_ptr<PermissionRequest>
+PermissionContextBase::CreatePermissionRequest(
+ content::WebContents* web_contents,
+ std::unique_ptr<PermissionRequestData> request_data,
+ PermissionRequest::PermissionDecidedCallbackWithLifetime permission_decided_callback,
+ base::OnceClosure request_finished_callback) const {
+ return std::make_unique<PermissionRequest>(
+ std::move(request_data), std::move(permission_decided_callback),
+ std::move(request_finished_callback), UsesAutomaticEmbargo());
+}
+
bool PermissionContextBase::UsesAutomaticEmbargo() const {
return true;
}
@@ -666,7 +677,8 @@ void PermissionContextBase::DecidePermission(
void PermissionContextBase::PermissionDecided(
const permissions::PermissionPromptDecision& decision,
- const PermissionRequestData& request_data) {
+ const PermissionRequestData& request_data,
+ content_settings::mojom::LifetimeMode lifetime_option) {
UserMadePermissionDecision(request_data.id, request_data.requesting_origin,
request_data.embedding_origin,
decision.overall_decision);
@@ -690,10 +702,10 @@ void PermissionContextBase::PermissionDecided(
// Check if `request` has `BrowserPermissionCallback`. The call back might be
// missing if a permission prompt was preignored and we already notified an
// origin about it.
- NotifyPermissionSet(request_data,
+ NotifyPermissionSetWithLifetime(request_data,
request->second.second ? std::move(request->second.second)
: base::DoNothing(),
- persist, decision);
+ persist, decision, lifetime_option);
}
content::BrowserContext* PermissionContextBase::browser_context() const {
@@ -776,6 +788,29 @@ void PermissionContextBase::NotifyPermissionSet(
BrowserPermissionCallback callback,
bool persist,
const permissions::PermissionPromptDecision& decision) {
+ NotifyPermissionSetImpl(request_data, std::move(callback),
+ persist, decision, /*use_lifetime_option*/ false,
+ content_settings::mojom::LifetimeMode::ALWAYS);
+}
+
+void PermissionContextBase::NotifyPermissionSetWithLifetime(
+ const PermissionRequestData& request_data,
+ BrowserPermissionCallback callback,
+ bool persist,
+ const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option) {
+ NotifyPermissionSetImpl(request_data, std::move(callback),
+ persist, decision, /*use_lifetime_option*/ true,
+ lifetime_option);
+}
+
+void PermissionContextBase::NotifyPermissionSetImpl(
+ const PermissionRequestData& request_data,
+ BrowserPermissionCallback callback,
+ bool persist,
+ const permissions::PermissionPromptDecision& decision,
+ bool use_lifetime_option,
+ content_settings::mojom::LifetimeMode lifetime_option) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Note that rfh may be null, see crbug.com/426909787.
auto* rfh = content::RenderFrameHost::FromID(
@@ -791,9 +826,9 @@ void PermissionContextBase::NotifyPermissionSet(
if (persist) {
// Clone new value, because we need it again for the callback.
- UpdateSetting(
+ UpdateSettingImpl(
request_data, new_value,
- decision.overall_decision == PermissionDecision::kAllowThisTime);
+ decision.overall_decision == PermissionDecision::kAllowThisTime, use_lifetime_option, lifetime_option);
}
if (decision.is_final) {
@@ -853,6 +888,17 @@ void PermissionContextBase::UpdateSetting(
const PermissionRequestData& request_data,
PermissionSetting setting,
bool is_one_time) {
+ UpdateSettingImpl(request_data, std::move(setting),
+ is_one_time,
+ /*use_lifetime_option*/ false,
+ content_settings::mojom::LifetimeMode::ALWAYS);
+}
+
+void PermissionContextBase::UpdateSettingImpl(const PermissionRequestData& request_data,
+ PermissionSetting setting,
+ bool is_one_time,
+ bool use_lifetime_option,
+ content_settings::mojom::LifetimeMode lifetime_option) {
DCHECK_EQ(request_data.requesting_origin,
request_data.requesting_origin.DeprecatedGetOriginAsURL());
DCHECK_EQ(request_data.embedding_origin,
@@ -862,6 +908,8 @@ void PermissionContextBase::UpdateSetting(
constraints.set_session_model(
is_one_time ? content_settings::mojom::SessionModel::ONE_TIME
: content_settings::mojom::SessionModel::DURABLE);
+ if (use_lifetime_option)
+ constraints = content_settings::GetConstraintSessionExpiration(lifetime_option);
// The unused permissions module in Safety check will revoke unused site
// permissions after a finite amount of time if the permission can be revoked.
diff --git a/components/permissions/permission_context_base.h b/components/permissions/permission_context_base.h
--- a/components/permissions/permission_context_base.h
+++ b/components/permissions/permission_context_base.h
@@ -205,6 +205,17 @@ class PermissionContextBase : public content_settings::Observer {
// Updates stored setting if persist is set, updates tab indicators
// and runs the callback to finish the request.
+ void NotifyPermissionSetImpl(const PermissionRequestData& request_data,
+ BrowserPermissionCallback callback,
+ bool persist,
+ const permissions::PermissionPromptDecision& decision,
+ bool use_lifetime_option,
+ content_settings::mojom::LifetimeMode lifetime_option);
+ virtual void NotifyPermissionSetWithLifetime(const PermissionRequestData& request_data,
+ BrowserPermissionCallback callback,
+ bool persist,
+ const permissions::PermissionPromptDecision& decision,
+ content_settings::mojom::LifetimeMode lifetime_option);
virtual void NotifyPermissionSet(
const PermissionRequestData& request_data,
BrowserPermissionCallback callback,
@@ -221,6 +232,11 @@ class PermissionContextBase : public content_settings::Observer {
// Store the decided permission state. Virtual since the permission might be
// stored with different restrictions (for example for desktop notifications).
+ void UpdateSettingImpl(const PermissionRequestData& request_data,
+ PermissionSetting setting,
+ bool is_one_time,
+ bool use_lifetime_option,
+ content_settings::mojom::LifetimeMode lifetime_option);
virtual void UpdateSetting(const PermissionRequestData& request_data,
PermissionSetting setting,
bool is_one_time);
@@ -250,6 +266,12 @@ class PermissionContextBase : public content_settings::Observer {
PermissionRequest::PermissionDecidedCallback permission_decided_callback,
base::OnceClosure request_finished_callback) const;
+ virtual std::unique_ptr<PermissionRequest> CreatePermissionRequest(
+ content::WebContents* web_contents,
+ std::unique_ptr<PermissionRequestData> request_data,
+ PermissionRequest::PermissionDecidedCallbackWithLifetime permission_decided_callback,
+ base::OnceClosure request_finished_callback) const;
+
// Implementors can override this method to avoid using automatic embargo.
virtual bool UsesAutomaticEmbargo() const;
@@ -303,7 +325,8 @@ class PermissionContextBase : public content_settings::Observer {
// This is the callback for PermissionRequest and is called once the user
// allows/blocks/dismisses a permission prompt.
void PermissionDecided(const permissions::PermissionPromptDecision& decision,
- const PermissionRequestData& request_data);
+ const PermissionRequestData& request_data,
+ content_settings::mojom::LifetimeMode lifetime_option);
raw_ptr<content::BrowserContext> browser_context_;
const ContentSettingsType content_settings_type_;
diff --git a/components/permissions/permission_prompt.h b/components/permissions/permission_prompt.h
--- a/components/permissions/permission_prompt.h
+++ b/components/permissions/permission_prompt.h
@@ -70,8 +70,9 @@ class PermissionPrompt {
virtual GURL GetEmbeddingOrigin() const = 0;
virtual void Accept(const PromptOptions& prompt_options) = 0;
- virtual void AcceptThisTime(const PromptOptions& prompt_options) = 0;
+ virtual void AcceptThisTime(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetime_option) = 0;
virtual void Deny(const PromptOptions& prompt_options) = 0;
+ virtual void DenyThisTime(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetime_option) = 0;
virtual void Dismiss(const PromptOptions& prompt_options) = 0;
virtual void Ignore(const PromptOptions& prompt_options) = 0;
virtual void SwitchToLoudPrompt() = 0;
diff --git a/components/permissions/permission_request.cc b/components/permissions/permission_request.cc
--- a/components/permissions/permission_request.cc
+++ b/components/permissions/permission_request.cc
@@ -49,6 +49,16 @@ PermissionRequest::PermissionRequest(
request_finished_callback_(std::move(request_finished_callback)),
uses_automatic_embargo_(uses_automatic_embargo) {}
+PermissionRequest::PermissionRequest(
+ std::unique_ptr<PermissionRequestData> request_data,
+ PermissionDecidedCallbackWithLifetime permission_decided_callback,
+ base::OnceClosure request_finished_callback,
+ bool uses_automatic_embargo)
+ : data_(std::move(request_data)),
+ permission_decided_callback_withlifetime_(std::move(permission_decided_callback)),
+ request_finished_callback_(std::move(request_finished_callback)),
+ uses_automatic_embargo_(uses_automatic_embargo) {}
+
PermissionRequest::~PermissionRequest() {
std::move(request_finished_callback_).Run();
}
@@ -511,7 +521,19 @@ PermissionRequest::GetGeolocationPromptType() const {
}
void PermissionRequest::PermissionGranted(const PromptOptions& prompt_options,
- bool is_one_time) {
+ bool is_one_time,
+ content_settings::mojom::LifetimeMode lifetime_option) {
+ if (permission_decided_callback_withlifetime_) {
+ std::move(permission_decided_callback_withlifetime_)
+ .Run(PermissionPromptDecision{.overall_decision =
+ is_one_time
+ ? PermissionDecision::kAllowThisTime
+ : PermissionDecision::kAllow,
+ .prompt_options = prompt_options,
+ .is_final = true},
+ /*request_data=*/*data_, lifetime_option);
+ return;
+ }
std::move(permission_decided_callback_)
.Run(PermissionPromptDecision{.overall_decision =
is_one_time
@@ -522,7 +544,16 @@ void PermissionRequest::PermissionGranted(const PromptOptions& prompt_options,
/*request_data=*/*data_);
}
-void PermissionRequest::PermissionDenied() {
+void PermissionRequest::PermissionDenied(content_settings::mojom::LifetimeMode lifetime_option) {
+ if (permission_decided_callback_withlifetime_) {
+ std::move(permission_decided_callback_withlifetime_)
+ .Run(PermissionPromptDecision{.overall_decision =
+ PermissionDecision::kDeny,
+ .prompt_options = std::monostate(),
+ .is_final = true},
+ /*request_data=*/*data_, lifetime_option);
+ return;
+ }
std::move(permission_decided_callback_)
.Run(PermissionPromptDecision{.overall_decision =
PermissionDecision::kDeny,
@@ -532,6 +563,14 @@ void PermissionRequest::PermissionDenied() {
}
void PermissionRequest::Cancelled(bool is_final_decision) {
+ if (permission_decided_callback_withlifetime_) {
+ permission_decided_callback_withlifetime_.Run(
+ PermissionPromptDecision{.overall_decision = PermissionDecision::kNone,
+ .prompt_options = std::monostate(),
+ .is_final = is_final_decision},
+ /*request_data=*/*data_, content_settings::mojom::LifetimeMode::ALWAYS);
+ return;
+ }
if (permission_decided_callback_) {
permission_decided_callback_.Run(
PermissionPromptDecision{.overall_decision = PermissionDecision::kNone,
diff --git a/components/permissions/permission_request.h b/components/permissions/permission_request.h
--- a/components/permissions/permission_request.h
+++ b/components/permissions/permission_request.h
@@ -54,6 +54,11 @@ class PermissionRequest {
base::RepeatingCallback<void(const PermissionPromptDecision&,
const PermissionRequestData&)>;
+ using PermissionDecidedCallbackWithLifetime = base::RepeatingCallback<void(
+ const PermissionPromptDecision&,
+ const PermissionRequestData& /*request_data*/,
+ content_settings::mojom::LifetimeMode /*lifetime_option*/)>;
+
// `permission_decided_callback` is called when the permission request is
// resolved by the user (see comment on PermissionDecidedCallback above).
// `request_finished_callback` is called when the permission request is being
@@ -68,6 +73,11 @@ class PermissionRequest {
base::OnceClosure request_finished_callback = base::DoNothing(),
bool uses_automatic_embargo = true);
+ PermissionRequest(std::unique_ptr<PermissionRequestData> request_data,
+ PermissionDecidedCallbackWithLifetime permission_decided_callback,
+ base::OnceClosure request_finished_callback = base::DoNothing(),
+ bool uses_automatic_embargo = true);
+
PermissionRequest(const PermissionRequest&) = delete;
PermissionRequest& operator=(const PermissionRequest&) = delete;
@@ -187,10 +197,10 @@ class PermissionRequest {
// If |is_one_time| is true the permission will last until all tabs of
// |origin| are closed or navigated away from, and then the permission will
// automatically expire after 1 day.
- void PermissionGranted(const PromptOptions& prompt_options, bool is_one_time);
+ void PermissionGranted(const PromptOptions& prompt_options, bool is_one_time, content_settings::mojom::LifetimeMode lifetime_option);
// Called when the user has denied the requested permission.
- void PermissionDenied();
+ void PermissionDenied(content_settings::mojom::LifetimeMode lifetime_option);
// Called when the user has cancelled the permission request. This
// corresponds to a denial, but is segregated in case the context needs to
@@ -254,6 +264,9 @@ class PermissionRequest {
// Called once a decision is made about the permission.
PermissionDecidedCallback permission_decided_callback_;
+ // Called once a decision is made about the permission (with lifetime option).
+ PermissionDecidedCallbackWithLifetime permission_decided_callback_withlifetime_;
+
// Called when the request is finished to perform bookkeeping tasks.
base::OnceClosure request_finished_callback_;
diff --git a/components/permissions/permission_request_manager.cc b/components/permissions/permission_request_manager.cc
--- a/components/permissions/permission_request_manager.cc
+++ b/components/permissions/permission_request_manager.cc
@@ -212,12 +212,12 @@ void PermissionRequestManager::AddRequest(
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDenyPermissionPrompts)) {
- request->PermissionDenied();
+ request->PermissionDenied(content_settings::mojom::LifetimeMode::ALWAYS);
return;
}
if (display::Screen::Get()->IsHeadless()) {
- request->PermissionDenied();
+ request->PermissionDenied(content_settings::mojom::LifetimeMode::ALWAYS);
return;
}
@@ -296,9 +296,9 @@ void PermissionRequestManager::AddRequest(
.selected_accuracy = GeolocationAccuracy::kPrecise})
: std::monostate();
if (should_auto_approve_request == PermissionAction::GRANTED) {
- request->PermissionGranted(prompt_options, /*is_one_time=*/false);
+ request->PermissionGranted(prompt_options, /*is_one_time=*/false, content_settings::mojom::LifetimeMode::UNTIL_ORIGIN_CLOSED);
} else if (should_auto_approve_request == PermissionAction::GRANTED_ONCE) {
- request->PermissionGranted(prompt_options, /*is_one_time=*/true);
+ request->PermissionGranted(prompt_options, /*is_one_time=*/true, content_settings::mojom::LifetimeMode::UNTIL_ORIGIN_CLOSED);
}
return;
}
@@ -638,7 +638,8 @@ void PermissionRequestManager::Accept(const PromptOptions& prompt_options) {
StorePermissionActionForUMA(request->requesting_origin(),
request->request_type(), action);
PermissionGrantedIncludingDuplicates(request.get(), prompt_options,
- /*is_one_time=*/false);
+ /*is_one_time=*/false,
+ content_settings::mojom::LifetimeMode::ALWAYS);
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
std::optional<ContentSettingsType> content_settings_type =
@@ -657,7 +658,7 @@ void PermissionRequestManager::Accept(const PromptOptions& prompt_options) {
}
void PermissionRequestManager::AcceptThisTime(
- const PromptOptions& prompt_options) {
+ const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode mode) {
CHECK_EQ(std::holds_alternative<GeolocationPromptOptions>(prompt_options),
requests_[0]->GetContentSettingsType() ==
ContentSettingsType::GEOLOCATION_WITH_OPTIONS)
@@ -676,7 +677,7 @@ void PermissionRequestManager::AcceptThisTime(
StorePermissionActionForUMA(request->requesting_origin(),
request->request_type(), action);
PermissionGrantedIncludingDuplicates(request.get(), prompt_options,
- /*is_one_time=*/true);
+ /*is_one_time=*/true, mode);
}
NotifyRequestDecided(action);
@@ -688,6 +689,16 @@ void PermissionRequestManager::Deny(const PromptOptions& prompt_options) {
requests_[0]->GetContentSettingsType() ==
ContentSettingsType::GEOLOCATION_WITH_OPTIONS);
+ Deny_(prompt_options, content_settings::mojom::LifetimeMode::ALWAYS);
+}
+
+void PermissionRequestManager::DenyThisTime(const PromptOptions& prompt_options,
+ content_settings::mojom::LifetimeMode mode) {
+ Deny_(prompt_options, mode);
+}
+
+void PermissionRequestManager::Deny_(const PromptOptions& prompt_options,
+ content_settings::mojom::LifetimeMode lifetime_option) {
if (ignore_callbacks_from_prompt_) {
return;
}
@@ -708,7 +719,7 @@ void PermissionRequestManager::Deny(const PromptOptions& prompt_options) {
for (const auto& request : requests_) {
StorePermissionActionForUMA(request->requesting_origin(),
request->request_type(), action);
- PermissionDeniedIncludingDuplicates(request.get());
+ PermissionDeniedIncludingDuplicates(request.get(), lifetime_option);
}
NotifyRequestDecided(action);
@@ -1462,32 +1473,33 @@ PermissionRequestManager::VisitDuplicateRequests(
void PermissionRequestManager::PermissionGrantedIncludingDuplicates(
PermissionRequest* request,
const PromptOptions& prompt_options,
- bool is_one_time) {
+ bool is_one_time,
+ content_settings::mojom::LifetimeMode lifetime_option) {
CHECK(RequestExistsExactlyOnce(request, pending_permission_requests_,
requests_))
<< "Only requests in [pending_permission_]requests_ can have duplicates";
- request->PermissionGranted(prompt_options, is_one_time);
+ request->PermissionGranted(prompt_options, is_one_time, lifetime_option);
VisitDuplicateRequests(
base::BindRepeating(
- [](const PromptOptions& prompt_options, bool is_one_time,
+ [](const PromptOptions& prompt_options, bool is_one_time, content_settings::mojom::LifetimeMode lifetime_option,
const std::unique_ptr<PermissionRequest>& request) {
- request->PermissionGranted(prompt_options, is_one_time);
+ request->PermissionGranted(prompt_options, is_one_time, lifetime_option);
},
- prompt_options, is_one_time),
+ prompt_options, is_one_time, lifetime_option),
request);
}
void PermissionRequestManager::PermissionDeniedIncludingDuplicates(
- PermissionRequest* request) {
+ PermissionRequest* request, content_settings::mojom::LifetimeMode lifetime_option) {
CHECK(RequestExistsExactlyOnce(request, pending_permission_requests_,
requests_))
<< "Only requests in [pending_permission_]requests_ can have duplicates";
- request->PermissionDenied();
+ request->PermissionDenied(lifetime_option);
VisitDuplicateRequests(
base::BindRepeating(
- [](const std::unique_ptr<PermissionRequest>& request) {
- request->PermissionDenied();
- }),
+ [](content_settings::mojom::LifetimeMode lifetime_option, const std::unique_ptr<PermissionRequest>& request) {
+ request->PermissionDenied(lifetime_option);
+ }, lifetime_option),
request);
}
@@ -1785,7 +1797,7 @@ void PermissionRequestManager::DoAutoResponseForTesting() {
}
switch (auto_response_for_test_) {
case ACCEPT_ONCE:
- AcceptThisTime(auto_response_prompt_options_for_test_);
+ AcceptThisTime(auto_response_prompt_options_for_test_, content_settings::mojom::LifetimeMode::ONLY_THIS_TIME);
break;
case ACCEPT_ALL:
Accept(auto_response_prompt_options_for_test_);
diff --git a/components/permissions/permission_request_manager.h b/components/permissions/permission_request_manager.h
--- a/components/permissions/permission_request_manager.h
+++ b/components/permissions/permission_request_manager.h
@@ -188,8 +188,10 @@ class PermissionRequestManager
GURL GetRequestingOrigin() const override;
GURL GetEmbeddingOrigin() const override;
void Accept(const PromptOptions& prompt_options) override;
- void AcceptThisTime(const PromptOptions& prompt_options) override;
+ void AcceptThisTime(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetime_option) override;
void Deny(const PromptOptions& prompt_options) override;
+ void Deny_(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetime_option);
+ void DenyThisTime(const PromptOptions& prompt_options, content_settings::mojom::LifetimeMode lifetime_option) override;
void Dismiss(const PromptOptions& prompt_options) override;
void Ignore(const PromptOptions& prompt_options) override;
void FinalizeCurrentRequests() override;
@@ -448,9 +450,11 @@ class PermissionRequestManager
// Calls PermissionGranted on a request and all its duplicates.
void PermissionGrantedIncludingDuplicates(PermissionRequest* request,
const PromptOptions& prompt_options,
- bool is_one_time);
+ bool is_one_time,
+ content_settings::mojom::LifetimeMode lifetime_option);
// Calls PermissionDenied on a request and all its duplicates.
- void PermissionDeniedIncludingDuplicates(PermissionRequest* request);
+ void PermissionDeniedIncludingDuplicates(PermissionRequest* request,
+ content_settings::mojom::LifetimeMode lifetime_option);
// Calls Cancelled on a request and all its duplicates.
void CancelRequestIncludingDuplicates(PermissionRequest* request,
bool is_final_decision = true);
--