From e0bd1dcad32968f61bdc5f083fb2ed1d8e6c1b3f Mon Sep 17 00:00:00 2001 From: Carmelo Messina Date: Sun, 4 Feb 2024 17:22:09 +0100 Subject: [PATCH] #404 completed support for three state site settings and improve ui --- .../Content-settings-infrastructure.patch | 1158 ++++++++++++++++- 1 file changed, 1092 insertions(+), 66 deletions(-) diff --git a/build/patches/Content-settings-infrastructure.patch b/build/patches/Content-settings-infrastructure.patch index 3d018e67..f8a8826a 100644 --- a/build/patches/Content-settings-infrastructure.patch +++ b/build/patches/Content-settings-infrastructure.patch @@ -14,25 +14,37 @@ Require: bromite-build-utils.patch .../ChromeSiteSettingsDelegate.java | 17 +- .../installable/installed_webapp_bridge.cc | 2 +- .../settings/privacy_page/privacy_page.html | 1 + - .../settings/privacy_page/privacy_page.ts | 44 ++- + .../settings/privacy_page/privacy_page.ts | 77 +++- chrome/browser/resources/settings/route.ts | 2 + - .../settings_category_default_radio_group.ts | 7 + + ...settings_category_default_radio_group.html | 12 + + .../settings_category_default_radio_group.ts | 22 +- .../settings/site_settings/site_details.html | 1 + - .../settings/site_settings/site_details.ts | 16 +- - .../site_settings_page/site_settings_page.ts | 28 +- - .../site_settings_page_util.ts | 55 ++++ + .../settings/site_settings/site_details.ts | 33 +- + .../site_details_permission.html | 8 +- + .../site_settings/site_details_permission.ts | 44 ++ + .../site_settings/site_settings_mixin.ts | 18 + + .../site_settings_page/site_settings_page.ts | 30 +- + .../site_settings_page_util.ts | 55 +++ chrome/browser/ui/BUILD.gn | 1 + - .../views/page_info/page_info_view_factory.cc | 13 + - .../settings_localized_strings_provider.cc | 39 +++ + .../controls/rich_controls_container_view.h | 7 + + .../ui/views/page_info/page_info_main_view.cc | 27 +- + .../views/page_info/page_info_view_factory.cc | 19 + + .../views/page_info/page_info_view_factory.h | 3 + + .../page_info/permission_toggle_row_view.cc | 163 ++++++- + .../page_info/permission_toggle_row_view.h | 18 +- + .../settings_localized_strings_provider.cc | 54 +++ .../ui/webui/settings/site_settings_helper.cc | 34 +- + .../browser_ui/settings/android/BUILD.gn | 1 + + .../preference_spinner_single_widget.xml | 92 ++++ + .../settings/SpinnerPreference.java | 24 + .../browser_ui/site_settings/android/BUILD.gn | 18 + .../site_settings/AllSiteSettings.java | 5 +- - .../BromiteCustomContentSetting.java | 139 ++++++++ - .../BromiteCustomContentSettingImpl.java | 307 ++++++++++++++++++ - ...tomTriStateSiteSettingsPreferenceImpl.java | 24 ++ + .../BromiteCustomContentSetting.java | 155 +++++++ + .../BromiteCustomContentSettingImpl.java | 409 ++++++++++++++++++ + ...tomTriStateSiteSettingsPreferenceImpl.java | 24 + .../ContentSettingsResources.java | 14 +- .../site_settings/SingleCategorySettings.java | 50 ++- - .../site_settings/SingleWebsiteSettings.java | 26 +- + .../site_settings/SingleWebsiteSettings.java | 58 ++- .../site_settings/SiteSettings.java | 14 +- .../site_settings/SiteSettingsCategory.java | 18 +- .../site_settings/SiteSettingsDelegate.java | 2 + @@ -41,7 +53,7 @@ Require: bromite-build-utils.patch .../WebsitePermissionsFetcher.java | 4 +- .../WebsitePreferenceBridge.java | 3 +- .../impl/include_all_directory.java | 1 + - ...miteCustomContentSettingImplBase.java.tmpl | 48 +++ + ...miteCustomContentSettingImplBase.java.tmpl | 48 ++ .../bromite_content_settings/placeholder.txt | 1 + components/content_settings/android/BUILD.gn | 1 + .../content_settings/core/browser/BUILD.gn | 7 + @@ -49,7 +61,7 @@ Require: bromite-build-utils.patch .../core/browser/content_settings_registry.cc | 2 + .../core/browser/content_settings_uma_util.cc | 3 +- .../core/browser/content_settings_utils.cc | 12 + - .../core/browser/website_settings_info.h | 35 ++ + .../core/browser/website_settings_info.h | 38 ++ .../core/browser/website_settings_registry.cc | 6 + .../core/browser/website_settings_registry.h | 1 + .../content_settings/core/common/BUILD.gn | 7 + @@ -58,7 +70,7 @@ Require: bromite-build-utils.patch .../core/common/content_settings.h | 10 + .../core/common/content_settings.mojom | 6 + .../common/content_settings_mojom_traits.cc | 12 +- - .../common/content_settings_mojom_traits.h | 24 ++ + .../common/content_settings_mojom_traits.h | 24 + .../common/content_settings_param_traits.h | 2 +- .../core/common/content_settings_types.h | 4 +- .../renderer/content_settings_agent_impl.cc | 33 ++ @@ -72,7 +84,8 @@ Require: bromite-build-utils.patch .../platform/web_content_settings_client.h | 5 + .../execution_context/execution_context.cc | 16 + .../execution_context/execution_context.h | 5 + - 61 files changed, 1194 insertions(+), 45 deletions(-) + 73 files changed, 1821 insertions(+), 76 deletions(-) + create mode 100644 components/browser_ui/settings/android/java/res/layout/preference_spinner_single_widget.xml create mode 100644 components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BromiteCustomContentSetting.java create mode 100644 components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BromiteCustomContentSettingImpl.java create mode 100644 components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BromiteCustomTriStateSiteSettingsPreferenceImpl.java @@ -147,9 +160,37 @@ diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/ diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts --- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts -@@ -71,7 +71,49 @@ export class SettingsPrivacyPageElement extends SettingsPrivacyPageElementBase { +@@ -47,6 +47,7 @@ import {SiteSettingsPrefsBrowserProxy, SiteSettingsPrefsBrowserProxyImpl} from ' + + import {PrivacyGuideAvailabilityMixin} from './privacy_guide/privacy_guide_availability_mixin.js'; + import {getTemplate} from './privacy_page.html.js'; ++import { SettingsCategoryDefaultRadioGroupElement } from '../site_settings/settings_category_default_radio_group.js'; + + interface BlockAutoplayStatus { + enabled: boolean; +@@ -70,8 +71,82 @@ export class SettingsPrivacyPageElement extends SettingsPrivacyPageElementBase { + return 'settings-privacy-page'; } ++ static getSettingTemplate(template: HTMLTemplateElement, ++ name: string) : SettingsCategoryDefaultRadioGroupElement | undefined { ++ let value : SettingsCategoryDefaultRadioGroupElement | undefined = undefined; ++ let page : any = template.content!.querySelector("settings-animated-pages"); ++ ++ page.querySelectorAll("template")!.forEach( ++ (subTemplate: HTMLTemplateElement) => { ++ subTemplate.content.querySelectorAll("settings-category-default-radio-group").forEach( ++ (radio: any) => { ++ let setting = radio.getAttribute("category") ++ .replace("[[contentSettingsTypesEnum_.", "") ++ .replace("]]", ""); ++ if ((ContentSettingsTypes as any)[setting] === name) ++ value = radio; ++ }); ++ }); ++ return value; ++ } ++ static get template() { - return getTemplate(); + let template = getTemplate(); @@ -160,36 +201,49 @@ diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/ch + let name = obj["name"]; + let tag_name = obj["tag_ui"]; if (!tag_name) tag_name = obj["name"]; + -+ let template = document.createElement("settings-subpage"); -+ template.setAttribute("page-title", loadTimeData.getString(`brSiteSettings${name}`)); -+ template.setAttribute("search-title", loadTimeData.getString("siteSettingsAllSitesSearch")); -+ template.setAttribute("search-term", "{{searchFilter_}}"); ++ let existingSetting = this.getSettingTemplate(template, name); ++ if (existingSetting) { ++ if (loadTimeData.valueExists(`brSiteSettings${name}Ask`)) { ++ existingSetting.setAttribute("ask-option-label", loadTimeData.getString(`brSiteSettings${name}Ask`)); ++ existingSetting.setAttribute("ask-option-icon", `br-settings:${name}-off`); ++ } ++ continue; ++ } ++ ++ let subpage = document.createElement("settings-subpage"); ++ subpage.setAttribute("page-title", loadTimeData.getString(`brSiteSettings${name}`)); ++ subpage.setAttribute("search-title", loadTimeData.getString("siteSettingsAllSitesSearch")); ++ subpage.setAttribute("search-term", "{{searchFilter_}}"); + + let divElement = document.createElement("div"); + divElement.setAttribute("class", "content-settings-header secondary"); + divElement.innerText = loadTimeData.getString(`brSiteSettings${name}Description`); -+ template.appendChild(divElement); ++ subpage.appendChild(divElement); + -+ let radioGroup = document.createElement("settings-category-default-radio-group"); ++ let radioGroup = existingSetting ?? document.createElement("settings-category-default-radio-group"); + radioGroup.setAttribute("category", name); + radioGroup.setAttribute("allow-option-label", loadTimeData.getString(`brSiteSettings${name}Allowed`)); + radioGroup.setAttribute("allow-option-icon", `br-settings:${name}`); + radioGroup.setAttribute("block-option-label", loadTimeData.getString(`brSiteSettings${name}Blocked`)); + radioGroup.setAttribute("block-option-icon", `br-settings:${name}-off`); -+ template.appendChild(radioGroup); ++ if (loadTimeData.valueExists(`brSiteSettings${name}Ask`)) { ++ radioGroup.setAttribute("ask-option-label", loadTimeData.getString(`brSiteSettings${name}Ask`)); ++ radioGroup.setAttribute("ask-option-icon", `br-settings:${name}-off`); ++ } ++ subpage.appendChild(radioGroup); + + let exceptions = document.createElement("category-setting-exceptions"); + exceptions.setAttribute("category", name); + exceptions.setAttribute("allow-header", loadTimeData.getString(`brSiteSettings${name}AllowedExceptions`)); + exceptions.setAttribute("block-header", loadTimeData.getString(`brSiteSettings${name}BlockedExceptions`)); + exceptions.setAttribute("search-filter", "[[searchFilter_]]"); -+ template.appendChild(exceptions); ++ subpage.appendChild(exceptions); + + let tag = document.createElement("template"); + tag.setAttribute("is", "dom-if"); + tag.setAttribute("route-path", `/content/${tag_name}`); + tag.setAttribute("no-search", ""); -+ tag.content.appendChild(template); ++ tag.content.appendChild(subpage); + + content.parentElement!.insertBefore(tag, content); + } @@ -217,23 +271,101 @@ diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resourc } /** +diff --git a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html +--- a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html ++++ b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.html +@@ -53,5 +53,17 @@ + icon="[[blockOptionIcon]]" + no-collapse> + ++ ++ + + diff --git a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts --- a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts +++ b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts -@@ -161,6 +161,13 @@ export class SettingsCategoryDefaultRadioGroupElement extends +@@ -29,6 +29,7 @@ import {ContentSettingProvider, DefaultContentSetting} from './site_settings_pre + export enum SiteContentRadioSetting { + DISABLED = 0, + ENABLED = 1, ++ ASK = 2, + } + + export interface SettingsCategoryDefaultRadioGroupElement { +@@ -76,6 +77,10 @@ export class SettingsCategoryDefaultRadioGroupElement extends + blockOptionSubLabel: String, + blockOptionIcon: String, + ++ askOptionLabel: String, ++ askOptionSubLabel: String, ++ askOptionIcon: String, ++ + siteContentRadioSettingEnum_: { + type: Object, + value: SiteContentRadioSetting, +@@ -111,6 +116,9 @@ export class SettingsCategoryDefaultRadioGroupElement extends + blockOptionLabel: string; + blockOptionSubLabel: string; + blockOptionIcon: string; ++ askOptionLabel: string; ++ askOptionSubLabel: string; ++ askOptionIcon: string; + private pref_: chrome.settingsPrivate.PrefObject; + + override ready() { +@@ -121,6 +129,13 @@ export class SettingsCategoryDefaultRadioGroupElement extends + (category: ContentSettingsTypes) => this.onCategoryChanged_(category)); + } + ++ private showAskSetting_( ++ category: ContentSettingsTypes): boolean { ++ let obj = this.getSettingData(category); ++ if (obj) return obj["allowed_ask"] === "1"; ++ return false; ++ } ++ + private getAllowOptionForCategory_(): ContentSetting { + switch (this.category) { + case ContentSettingsTypes.ADS: +@@ -161,6 +176,8 @@ export class SettingsCategoryDefaultRadioGroupElement extends // "Ask" vs "Blocked". return ContentSetting.ASK; default: -+ for (let index=0; index < loadTimeData.getInteger("br_cs_count"); index++) { -+ let obj = JSON.parse(loadTimeData.getString("br_cs_" + index)); -+ let name = obj["name"]; -+ if (this.category == name) { -+ return ContentSetting.ALLOW; -+ } -+ } ++ let obj = this.getSettingData(this.category); ++ if (obj) return ContentSetting.ALLOW; assertNotReached('Invalid category: ' + this.category); } } +@@ -185,6 +202,7 @@ export class SettingsCategoryDefaultRadioGroupElement extends + /** @type {!ContentSetting} */ (this.getAllowOptionForCategory_()); + this.browserProxy.setDefaultValueForContentType( + this.category, ++ this.pref_.value === SiteContentRadioSetting.ASK ? "ask" : + this.categoryEnabled_ ? allowOption : ContentSetting.BLOCK); + } + +@@ -216,7 +234,9 @@ export class SettingsCategoryDefaultRadioGroupElement extends + } + + const enabled = this.computeIsSettingEnabled(update.setting); +- const prefValue = enabled ? SiteContentRadioSetting.ENABLED : ++ const ask = this.computeIsSettingAsk(update.setting); ++ const prefValue = ask ? SiteContentRadioSetting.ASK : ++ enabled ? SiteContentRadioSetting.ENABLED : + SiteContentRadioSetting.DISABLED; + + this.set('pref_.value', prefValue); diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html --- a/chrome/browser/resources/settings/site_settings/site_details.html +++ b/chrome/browser/resources/settings/site_settings/site_details.html @@ -246,9 +378,24 @@ diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b diff --git a/chrome/browser/resources/settings/site_settings/site_details.ts b/chrome/browser/resources/settings/site_settings/site_details.ts --- a/chrome/browser/resources/settings/site_settings/site_details.ts +++ b/chrome/browser/resources/settings/site_settings/site_details.ts -@@ -61,7 +61,21 @@ export class SiteDetailsElement extends SiteDetailsElementBase { +@@ -60,8 +60,39 @@ export class SiteDetailsElement extends SiteDetailsElementBase { + return 'site-details'; } ++ static getSettingTemplate(template: HTMLTemplateElement, ++ name: string) : SiteDetailsPermissionElement | undefined { ++ let value : SiteDetailsPermissionElement | undefined = undefined; ++ template.content.querySelectorAll("site-details-permission").forEach( ++ (element: any) => { ++ let setting = element.getAttribute("category") ++ .replace("[[contentSettingsTypesEnum_.", "") ++ .replace("]]", ""); ++ if ((ContentSettingsTypes as any)[setting] === name) ++ value = element; ++ }); ++ return value; ++ } ++ static get template() { - return getTemplate(); + let template = getTemplate(); @@ -258,6 +405,9 @@ diff --git a/chrome/browser/resources/settings/site_settings/site_details.ts b/c + let obj = JSON.parse(loadTimeData.getString("br_cs_" + index)); + let name = obj["name"]; + ++ if (this.getSettingTemplate(template, name)) ++ continue; ++ + let tag = document.createElement("site-details-permission"); + tag.setAttribute("category", name); + tag.setAttribute("icon", `br-settings:${name}`); @@ -269,6 +419,163 @@ diff --git a/chrome/browser/resources/settings/site_settings/site_details.ts b/c } static get properties() { +diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html +--- a/chrome/browser/resources/settings/site_settings/site_details_permission.html ++++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html +@@ -49,7 +49,9 @@ + + + + + +diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.ts b/chrome/browser/resources/settings/site_settings/site_details_permission.ts +--- a/chrome/browser/resources/settings/site_settings/site_details_permission.ts ++++ b/chrome/browser/resources/settings/site_settings/site_details_permission.ts +@@ -20,6 +20,7 @@ import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener + import {assert, assertNotReached} from 'chrome://resources/js/assert.js'; + import {sanitizeInnerHtml} from 'chrome://resources/js/parse_html_subset.js'; + import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; ++import {loadTimeData} from '../i18n_setup.js'; + + import {ChooserType, ContentSetting, ContentSettingsTypes, SiteSettingSource} from './constants.js'; + import {getTemplate} from './site_details_permission.html.js'; +@@ -267,15 +268,28 @@ export class SiteDetailsPermissionElement extends + return ''; + } + ++ let obj = this.getSettingData(category); + if (defaultSetting === ContentSetting.ASK || + defaultSetting === ContentSetting.IMPORTANT_CONTENT) { ++ if (obj) { ++ let v = this.askSettingString_(category, ""); ++ if (v !== "") return "(Default) " + v; ++ } + return this.i18n('siteSettingsActionAskDefault'); + } else if (defaultSetting === ContentSetting.ALLOW) { ++ if (obj) { ++ let v = this.allowSettingString_(category, ""); ++ if (v !== "") return "(Default) " + v; ++ } + if (this.useCustomSoundLabels_(category) && useAutomaticLabel) { + return this.i18n('siteSettingsActionAutomaticDefault'); + } + return this.i18n('siteSettingsActionAllowDefault'); + } else if (defaultSetting === ContentSetting.BLOCK) { ++ if (obj) { ++ let v = this.blockSettingString_(category, "", ""); ++ if (v !== "") return "(Default) " + v; ++ } + if (this.useCustomSoundLabels_(category)) { + return this.i18n('siteSettingsActionMuteDefault'); + } +@@ -294,12 +308,40 @@ export class SiteDetailsPermissionElement extends + private blockSettingString_( + category: ContentSettingsTypes, blockString: string, + muteString: string): string { ++ let obj = this.getSettingData(category); ++ if (obj) { ++ let propertyName = "brSiteSettings" + obj["name"] + "Blocked"; ++ if (loadTimeData.valueExists(propertyName)) ++ return loadTimeData.getString(propertyName); ++ } + if (this.useCustomSoundLabels_(category)) { + return muteString; + } + return blockString; + } + ++ private allowSettingString_( ++ category: ContentSettingsTypes, defaultString: string): string { ++ let obj = this.getSettingData(category); ++ if (obj) { ++ let propertyName = "brSiteSettings" + obj["name"] + "Allowed"; ++ if (loadTimeData.valueExists(propertyName)) ++ return loadTimeData.getString(propertyName); ++ } ++ return defaultString; ++ } ++ ++ private askSettingString_( ++ category: ContentSettingsTypes, defaultString: string): string { ++ let obj = this.getSettingData(category); ++ if (obj) { ++ let propertyName = "brSiteSettings" + obj["name"] + "Ask"; ++ if (loadTimeData.valueExists(propertyName)) ++ return loadTimeData.getString(propertyName); ++ } ++ return defaultString; ++ } ++ + /** + * @return true if |this| should be hidden. + */ +@@ -385,6 +427,8 @@ export class SiteDetailsPermissionElement extends + private showAskSetting_( + category: ContentSettingsTypes, setting: ContentSetting, + source: SiteSettingSource): boolean { ++ let obj = this.getSettingData(category); ++ if (obj) return obj["allowed_ask"] === "1"; + // For chooser-based permissions 'ask' takes the place of 'allow'. + if (category === ContentSettingsTypes.SERIAL_PORTS || + category === ContentSettingsTypes.USB_DEVICES || +diff --git a/chrome/browser/resources/settings/site_settings/site_settings_mixin.ts b/chrome/browser/resources/settings/site_settings/site_settings_mixin.ts +--- a/chrome/browser/resources/settings/site_settings/site_settings_mixin.ts ++++ b/chrome/browser/resources/settings/site_settings/site_settings_mixin.ts +@@ -11,6 +11,7 @@ import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/pol + + import {ContentSetting,ContentSettingsTypes, SiteSettingSource} from './constants.js'; + import {RawSiteException,SiteException,SiteSettingsPrefsBrowserProxy,SiteSettingsPrefsBrowserProxyImpl} from './site_settings_prefs_browser_proxy.js'; ++import {loadTimeData} from '../i18n_setup.js'; + // clang-format on + + type Constructor = new (...args: any[]) => T; +@@ -91,6 +92,21 @@ export const SiteSettingsMixin = dedupingMixin( + return setting !== ContentSetting.BLOCK; + } + ++ computeIsSettingAsk(setting: ContentSetting): boolean { ++ return setting === ContentSetting.ASK; ++ } ++ ++ getSettingData(category: ContentSettingsTypes): any { ++ for (let index=0; index < loadTimeData.getInteger("br_cs_count"); index++) { ++ let obj = JSON.parse(loadTimeData.getString("br_cs_" + index)); ++ let name = obj["name"]; ++ if (name == category) { ++ return obj; ++ } ++ } ++ return undefined; ++ } ++ + /** + * Converts a string origin/pattern to a URL. + * @param originOrPattern The origin/pattern to convert to URL. +@@ -171,6 +187,8 @@ export interface SiteSettingsMixinInterface { + browserProxy: SiteSettingsPrefsBrowserProxy; + category: ContentSettingsTypes; + computeIsSettingEnabled(setting: string): boolean; ++ computeIsSettingAsk(setting: string): boolean; ++ getSettingData(category: ContentSettingsTypes): any; + originRepresentation(origin: string): string; + toUrl(originOrPattern: string): URL|null; + expandSiteException(exception: RawSiteException): SiteException; diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts --- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts +++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts @@ -281,7 +588,7 @@ diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_ { route: routes.SITE_SETTINGS_ADS, id: Id.ADS, -@@ -371,10 +371,34 @@ function getCategoryItemMap(): Map { +@@ -371,10 +371,36 @@ function getCategoryItemMap(): Map { disabledLabel: 'trackingProtectionLinkRowSubLabel', }); } @@ -289,14 +596,16 @@ diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_ + let obj = JSON.parse(loadTimeData.getString("br_cs_" + index)); + let name = obj["name"]; + -+ categoryList.push({ -+ route: (routes as any)[`SITE_SETTINGS_${name.toUpperCase()}`], -+ id: name, -+ label: `brSiteSettings${name}`, -+ icon: `br-settings:${name}`, -+ enabledLabel: `brSiteSettings${name}Allowed`, -+ disabledLabel: `brSiteSettings${name}Blocked`, -+ }); ++ if (!categoryList.find(x=> x.id == name)) { ++ categoryList.push({ ++ route: (routes as any)[`SITE_SETTINGS_${name.toUpperCase()}`], ++ id: name, ++ label: `brSiteSettings${name}`, ++ icon: `br-settings:${name}`, ++ enabledLabel: `brSiteSettings${name}Allowed`, ++ disabledLabel: `brSiteSettings${name}Blocked`, ++ }); ++ } + } + categoryItemMap = new Map(categoryList.map(item => [item.id, item])); @@ -316,7 +625,7 @@ diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_ function buildItemListFromIds(orderedIdList: ContentSettingsTypes[]): CategoryListItem[] { const map = getCategoryItemMap(); -@@ -465,7 +489,7 @@ export class SettingsSiteSettingsPageElement extends +@@ -465,7 +491,7 @@ export class SettingsSiteSettingsPageElement extends Id.IMAGES, Id.POPUPS, ]), @@ -408,6 +717,92 @@ diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn "//components/enterprise/common:files_scan_data", "//components/feedback/proto", "//components/headless/policy", +diff --git a/chrome/browser/ui/views/controls/rich_controls_container_view.h b/chrome/browser/ui/views/controls/rich_controls_container_view.h +--- a/chrome/browser/ui/views/controls/rich_controls_container_view.h ++++ b/chrome/browser/ui/views/controls/rich_controls_container_view.h +@@ -42,6 +42,13 @@ class RichControlsContainerView : public views::FlexLayoutView { + return AddChildView(std::move(control_view)); + } + ++ template ++ T* AddControlUnderLabel(std::unique_ptr control_view) { ++ control_view->SetProperty(views::kInternalPaddingKey, ++ control_view->GetInsets()); ++ return labels_wrapper_->AddChildView(std::move(control_view)); ++ } ++ + int GetFirstLineHeight(); + gfx::Size FlexRule(const views::View* view, + const views::SizeBounds& maximum_size) const; +diff --git a/chrome/browser/ui/views/page_info/page_info_main_view.cc b/chrome/browser/ui/views/page_info/page_info_main_view.cc +--- a/chrome/browser/ui/views/page_info/page_info_main_view.cc ++++ b/chrome/browser/ui/views/page_info/page_info_main_view.cc +@@ -49,6 +49,7 @@ + #include "ui/views/controls/separator.h" + #include "ui/views/layout/box_layout.h" + #include "ui/views/layout/flex_layout.h" ++#include "ui/views/layout/table_layout.h" + #include "ui/views/view_class_properties.h" + + #if BUILDFLAG(FULL_SAFE_BROWSING) +@@ -243,8 +244,20 @@ void PageInfoMainView::SetPermissionInfo( + scroll_view->SetDrawOverflowIndicator(false); + auto* content_view = + scroll_view->SetContents(std::make_unique()); +- content_view->SetLayoutManager(std::make_unique()) +- ->SetOrientation(views::LayoutOrientation::kVertical); ++ ++ views::TableLayout* table_layout = ++ content_view->SetLayoutManager(std::make_unique()); ++ table_layout->AddColumn( ++ views::LayoutAlignment::kStretch, views::LayoutAlignment::kStretch, ++ views::TableLayout::kFixedSize, ++ views::TableLayout::ColumnSize::kFixed, ++ /*fixed_width=*/250, /*min_width=*/0) ++ .AddColumn( ++ views::LayoutAlignment::kStretch, views::LayoutAlignment::kStretch, ++ views::TableLayout::kFixedSize, ++ views::TableLayout::ColumnSize::kFixed, ++ /*fixed_width=*/250, /*min_width=*/0) ++ .AddRows(/*n=*/1, views::TableLayout::kFixedSize); + content_view->SetID(PageInfoViewFactory::VIEW_ID_PAGE_INFO_PERMISSION_VIEW); + content_view->SetProperty(views::kElementIdentifierKey, + kPermissionsElementId); +@@ -259,17 +272,24 @@ void PageInfoMainView::SetPermissionInfo( + } + } + ++ int count = 0; + for (const auto& permission : permission_info_list) { ++ if (++count % 2 == 0) ++ table_layout->AddRows(/*n=*/1, views::TableLayout::kFixedSize); + auto* toggle_row = + content_view->AddChildView(std::make_unique( + ui_delegate_, navigation_handler_, permission, should_show_spacer)); + toggle_row->AddObserver(this); ++ toggle_row->SetProperty(views::kMarginsKey, ++ gfx::Insets::TLBR(0, 0, 0, 0)); + toggle_row->SetProperty(views::kCrossAxisAlignmentKey, + views::LayoutAlignment::kStretch); + toggle_rows_.push_back(std::move(toggle_row)); + } + + for (auto& object : chosen_object_info_list) { ++ if (++count % 2 == 0) ++ table_layout->AddRows(/*n=*/1, views::TableLayout::kFixedSize); + // The view takes ownership of the object info. + auto object_view = std::make_unique( + std::move(object), +@@ -280,6 +300,9 @@ void PageInfoMainView::SetPermissionInfo( + content_view->AddChildView(std::move(object_view))); + } + ++ if (++count % 2 == 0) ++ content_view->AddChildView(std::make_unique()); ++ + const int controls_spacing = ChromeLayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_RELATED_CONTROL_VERTICAL); + reset_button_ = content_view->AddChildView( diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.cc b/chrome/browser/ui/views/page_info/page_info_view_factory.cc --- a/chrome/browser/ui/views/page_info/page_info_view_factory.cc +++ b/chrome/browser/ui/views/page_info/page_info_view_factory.cc @@ -420,7 +815,21 @@ diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.cc b/chrom #include "components/page_info/core/features.h" #include "components/page_info/core/proto/about_this_site_metadata.pb.h" #include "components/page_info/page_info.h" -@@ -507,6 +509,17 @@ const ui::ImageModel PageInfoViewFactory::GetPermissionIcon( +@@ -253,7 +255,13 @@ const ui::ImageModel PageInfoViewFactory::GetPermissionIcon( + ContentSetting setting = info.setting == CONTENT_SETTING_DEFAULT + ? info.default_setting + : info.setting; ++ return GetPermissionIcon(info, setting); ++} + ++// static ++const ui::ImageModel PageInfoViewFactory::GetPermissionIcon( ++ const PageInfo::PermissionInfo& info, ++ ContentSetting setting) { + // For guard content settings and Automatic Picture-in-Picture, ASK is treated + // as an "on" state. + const bool show_blocked_badge = +@@ -507,6 +515,17 @@ const ui::ImageModel PageInfoViewFactory::GetPermissionIcon( icon = &vector_icons::kPictureInPictureIcon; break; default: @@ -438,6 +847,287 @@ diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.cc b/chrom // All other |ContentSettingsType|s do not have icons on desktop or are // not shown in the Page Info bubble. NOTREACHED_NORETURN(); +diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.h b/chrome/browser/ui/views/page_info/page_info_view_factory.h +--- a/chrome/browser/ui/views/page_info/page_info_view_factory.h ++++ b/chrome/browser/ui/views/page_info/page_info_view_factory.h +@@ -83,6 +83,9 @@ class PageInfoViewFactory { + static const ui::ImageModel GetPermissionIcon( + const PageInfo::PermissionInfo& info); + ++ static const ui::ImageModel GetPermissionIcon( ++ const PageInfo::PermissionInfo& info, ContentSetting setting); ++ + // Returns the icon for the given object |info|. + static const ui::ImageModel GetChosenObjectIcon( + const PageInfoUI::ChosenObjectInfo& info, +diff --git a/chrome/browser/ui/views/page_info/permission_toggle_row_view.cc b/chrome/browser/ui/views/page_info/permission_toggle_row_view.cc +--- a/chrome/browser/ui/views/page_info/permission_toggle_row_view.cc ++++ b/chrome/browser/ui/views/page_info/permission_toggle_row_view.cc +@@ -35,6 +35,30 @@ + #include "ui/views/controls/label.h" + #include "ui/views/style/typography.h" + #include "ui/views/view_class_properties.h" ++#include "components/content_settings/core/browser/content_settings_registry.h" ++ ++namespace { ++ bool IsAllowed(const PageInfo::PermissionInfo& permission) { ++ if (permission.setting == CONTENT_SETTING_DEFAULT) ++ return permission.default_setting == CONTENT_SETTING_ALLOW; ++ else ++ return permission.setting == CONTENT_SETTING_ALLOW; ++ } ++ ++ bool IsBlocked(const PageInfo::PermissionInfo& permission) { ++ if (permission.setting == CONTENT_SETTING_DEFAULT) ++ return permission.default_setting == CONTENT_SETTING_BLOCK; ++ else ++ return permission.setting == CONTENT_SETTING_BLOCK; ++ } ++ ++ bool IsAsk(const PageInfo::PermissionInfo& permission) { ++ if (permission.setting == CONTENT_SETTING_DEFAULT) ++ return permission.default_setting == CONTENT_SETTING_ASK; ++ else ++ return permission.setting == CONTENT_SETTING_ASK; ++ } ++} + + PermissionToggleRowView::PermissionToggleRowView( + ChromePageInfoUiDelegate* delegate, +@@ -48,16 +72,12 @@ PermissionToggleRowView::PermissionToggleRowView( + // instead of adding it as the only child. + SetUseDefaultFillLayout(true); + row_view_ = AddChildView(std::make_unique()); ++ row_view_->SetCrossAxisAlignment(views::LayoutAlignment::kCenter); + + std::u16string toggle_accessible_name = + PageInfoUI::PermissionTypeToUIString(permission.type); + row_view_->SetTitle(toggle_accessible_name); + +- // Add extra details as sublabel. +- std::u16string detail = delegate->GetPermissionDetail(permission.type); +- if (!detail.empty()) +- row_view_->AddSecondaryLabel(detail); +- + if (permission.requesting_origin.has_value()) { + std::u16string requesting_origin_string; + switch (permission.type) { +@@ -115,6 +135,90 @@ void PermissionToggleRowView::PermissionChanged() { + } + } + ++void PermissionToggleRowView::OnShowOptionsMenu() { ++ sources_menu_runner_.reset(); ++ ++ ContentSettingsType type = permission_.type; ++ const content_settings::WebsiteSettingsInfo* setting_info = ++ content_settings::WebsiteSettingsRegistry::GetInstance()->Get(type); ++ ++ sources_menu_model_ = std::make_unique(this); ++ if (setting_info->allowed_ui() != 0) { ++ sources_menu_model_->AddCheckItemWithStringId(1, setting_info->allowed_ui()); ++ } else { ++ sources_menu_model_->AddCheckItem(1, u"Enabled"); ++ } ++ sources_menu_model_->SetIcon(sources_menu_model_->GetItemCount() - 1, ++ PageInfoViewFactory::GetPermissionIcon(permission_, CONTENT_SETTING_DEFAULT)); ++ ++ auto* content_setting_registry = ++ content_settings::ContentSettingsRegistry::GetInstance(); ++ auto* content_setting = content_setting_registry->Get(type); ++ if (content_setting->IsSettingValid(CONTENT_SETTING_ASK)) { ++ if (setting_info->ask_ui() != 0) { ++ sources_menu_model_->AddCheckItemWithStringId(3, setting_info->ask_ui()); ++ } else { ++ sources_menu_model_->AddCheckItem(3, u"Ask"); ++ } ++ sources_menu_model_->SetIcon(sources_menu_model_->GetItemCount() - 1, ++ PageInfoViewFactory::GetPermissionIcon(permission_, CONTENT_SETTING_ASK)); ++ } ++ ++ if (setting_info->blocked_ui() != 0) { ++ sources_menu_model_->AddCheckItemWithStringId(2, setting_info->blocked_ui()); ++ } else { ++ sources_menu_model_->AddCheckItem(2, u"Disabled"); ++ } ++ sources_menu_model_->SetIcon(sources_menu_model_->GetItemCount() - 1, ++ PageInfoViewFactory::GetPermissionIcon(permission_, CONTENT_SETTING_BLOCK)); ++ ++ sources_menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); ++ sources_menu_model_->AddCheckItem(4, u"Default"); ++ ++ //sources_menu_model_->ActivatedAt(0); ++ ++ // const gfx::Point point = choose_button_->GetMenuPosition(); ++ // const gfx::Point origin(point.x() - width(), point.y() - height()); ++ ++ sources_menu_runner_ = std::make_unique( ++ sources_menu_model_.get(), views::MenuRunner::COMBOBOX); ++ sources_menu_runner_->RunMenuAt( ++ choose_button_->GetWidget(), nullptr, ++ choose_button_->GetAnchorBoundsInScreen(), ++ views::MenuAnchorPosition::kTopLeft, ui::MENU_SOURCE_MOUSE); ++} ++ ++bool PermissionToggleRowView::IsCommandIdChecked(int command_id) const { ++ if (permission_.setting == CONTENT_SETTING_DEFAULT && command_id == 4) { ++ return true; ++ } else if (IsAllowed(permission_)) { ++ return command_id == 1; ++ } else if (IsBlocked(permission_)) { ++ return command_id == 2; ++ } else if (IsAsk(permission_)) { ++ return command_id == 3; ++ } ++ return false; ++} ++ ++void PermissionToggleRowView::ExecuteCommand(int command_id, int event_flags) { ++ switch(command_id) { ++ case 1: ++ permission_.setting = CONTENT_SETTING_ALLOW; ++ break; ++ case 2: ++ permission_.setting = CONTENT_SETTING_BLOCK; ++ break; ++ case 3: ++ permission_.setting = CONTENT_SETTING_ASK; ++ break; ++ case 4: ++ permission_.setting = CONTENT_SETTING_DEFAULT; ++ break; ++ } ++ PermissionChanged(); ++} ++ + void PermissionToggleRowView::OnToggleButtonPressed() { + PageInfoUI::ToggleBetweenAllowAndBlock(permission_); + PermissionChanged(); +@@ -123,24 +227,19 @@ void PermissionToggleRowView::OnToggleButtonPressed() { + void PermissionToggleRowView::InitForUserSource( + bool should_show_spacer_view, + const std::u16string& toggle_accessible_name) { +- const int icon_label_spacing = ChromeLayoutProvider::Get()->GetDistanceMetric( +- views::DISTANCE_RELATED_LABEL_HORIZONTAL); +- +- auto toggle_button = std::make_unique( +- base::BindRepeating(&PermissionToggleRowView::OnToggleButtonPressed, +- base::Unretained(this))); ++ auto toggle_button = std::make_unique( ++ base::BindRepeating(&PermissionToggleRowView::OnShowOptionsMenu, ++ base::Unretained(this)), ++ u""); ++ toggle_button->SetStyle(ui::ButtonStyle::kText); ++ toggle_button->SetHorizontalAlignment(gfx::ALIGN_LEFT); + toggle_button->SetID( + PageInfoViewFactory::VIEW_ID_PERMISSION_TOGGLE_ROW_TOGGLE_BUTTON); +- toggle_button->SetPreferredSize( +- gfx::Size(toggle_button->GetPreferredSize().width(), +- row_view_->GetFirstLineHeight())); +- toggle_button->SetProperty(views::kMarginsKey, +- gfx::Insets::VH(0, icon_label_spacing)); + toggle_button->SetTooltipText(PageInfoUI::PermissionTooltipUiString( + permission_.type, permission_.requesting_origin)); + toggle_button->SetAccessibleName(toggle_accessible_name); + +- toggle_button_ = row_view_->AddControl(std::move(toggle_button)); ++ choose_button_ = row_view_->AddControlUnderLabel(std::move(toggle_button)); + + const int icon_size = GetLayoutConstant(PAGE_INFO_ICON_SIZE); + // TODO(crbug.com/1011533): Remove separate handling of +@@ -187,9 +286,6 @@ void PermissionToggleRowView::InitForUserSource( + auto spacer_view = std::make_unique(); + spacer_view->SetPreferredSize(gfx::Size(icon_size, icon_size)); + spacer_view_ = row_view_->AddControl(std::move(spacer_view)); +- } else { +- toggle_button_->SetProperty( +- views::kMarginsKey, gfx::Insets::TLBR(0, icon_label_spacing, 0, 0)); + } + } + } +@@ -245,6 +341,33 @@ void PermissionToggleRowView::UpdateUiOnPermissionChanged() { + state_label_ = row_view_->AddSecondaryLabel(state_text); + } + } ++ ++ if (choose_button_) { ++ ContentSettingsType type = permission_.type; ++ const content_settings::WebsiteSettingsInfo* setting_info = ++ content_settings::WebsiteSettingsRegistry::GetInstance()->Get(type); ++ ++ std::u16string caption; ++ if (IsAllowed(permission_)) { ++ if (setting_info->allowed_ui() != 0) ++ caption = l10n_util::GetStringUTF16(setting_info->allowed_ui()); ++ else ++ caption = u"Allowed"; ++ } else if (IsBlocked(permission_)) { ++ if (setting_info->blocked_ui() != 0) ++ caption = l10n_util::GetStringUTF16(setting_info->blocked_ui()); ++ else ++ caption = u"Blocked"; ++ } else if (IsAsk(permission_)) { ++ if (setting_info->ask_ui() != 0) ++ caption = l10n_util::GetStringUTF16(setting_info->ask_ui()); ++ else ++ caption = u"Ask"; ++ } else { ++ caption = u"Unknown"; ++ } ++ choose_button_->SetText(caption); ++ } + } + + void PermissionToggleRowView::ResetPermission() { +diff --git a/chrome/browser/ui/views/page_info/permission_toggle_row_view.h b/chrome/browser/ui/views/page_info/permission_toggle_row_view.h +--- a/chrome/browser/ui/views/page_info/permission_toggle_row_view.h ++++ b/chrome/browser/ui/views/page_info/permission_toggle_row_view.h +@@ -14,6 +14,11 @@ + #include "ui/base/metadata/metadata_header_macros.h" + #include "ui/views/view.h" + ++#include "components/content_settings/core/browser/website_settings_registry.h" ++#include "chrome/browser/ui/views/controls/md_text_button_with_down_arrow.h" ++#include "ui/base/models/simple_menu_model.h" ++#include "ui/views/controls/menu/menu_runner.h" ++ + class ChromePageInfoUiDelegate; + class PageInfoNavigationHandler; + +@@ -29,7 +34,8 @@ class PageInfoBubbleViewTestApi; + // A view that shows a permission that a site is able to access, and + // allows the user to control via toggle whether that access is granted. Has a + // button that opens a subpage with more controls. +-class PermissionToggleRowView : public views::View { ++class PermissionToggleRowView : public views::View, ++ public ui::SimpleMenuModel::Delegate { + public: + METADATA_HEADER(PermissionToggleRowView); + PermissionToggleRowView(ChromePageInfoUiDelegate* delegate, +@@ -52,6 +58,12 @@ class PermissionToggleRowView : public views::View { + private: + friend class test::PageInfoBubbleViewTestApi; + ++ void OnShowOptionsMenu(); ++ ++ // ui::SimpleMenuModel::Delegate overrides: ++ bool IsCommandIdChecked(int command_id) const override; ++ void ExecuteCommand(int command_id, int event_flags) override; ++ + void OnToggleButtonPressed(); + void InitForUserSource(bool should_show_spacer_view, + const std::u16string& toggle_accessible_name); +@@ -65,6 +77,10 @@ class PermissionToggleRowView : public views::View { + raw_ptr toggle_button_ = nullptr; + raw_ptr spacer_view_ = nullptr; + ++ raw_ptr choose_button_ = nullptr; ++ std::unique_ptr sources_menu_model_; ++ std::unique_ptr sources_menu_runner_; ++ + raw_ptr delegate_ = nullptr; + raw_ptr navigation_handler_ = + nullptr; diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc @@ -449,34 +1139,47 @@ diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provide #include "build/branding_buildflags.h" #include "build/build_config.h" #include "build/buildflag.h" -@@ -72,6 +73,8 @@ +@@ -72,6 +73,9 @@ #include "components/google/core/common/google_util.h" #include "components/history/core/common/pref_names.h" #include "components/omnibox/common/omnibox_features.h" ++#include "components/content_settings/core/browser/content_settings_registry.h" +#include "components/content_settings/core/browser/website_settings_info.h" +#include "components/content_settings/core/browser/website_settings_registry.h" #include "components/password_manager/core/browser/leak_detection_dialog_utils.h" #include "components/password_manager/core/browser/manage_passwords_referrer.h" #include "components/password_manager/core/common/password_manager_features.h" -@@ -3628,6 +3631,42 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, +@@ -3628,6 +3632,56 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, policy_indicator::AddLocalizedStrings(html_source); AddSecurityKeysStrings(html_source); + content_settings::WebsiteSettingsRegistry* website_settings = + content_settings::WebsiteSettingsRegistry::GetInstance(); ++ auto* content_setting_registry = ++ content_settings::ContentSettingsRegistry::GetInstance(); + int index = 0; + for (const content_settings::WebsiteSettingsInfo* info : *website_settings) { + if (info->desktop_ui()) { ++ auto* content_setting = content_setting_registry->Get(info->type()); + std::string name = info->name(); + std::string prefix = "brSiteSettings" + name; + -+ html_source->AddLocalizedString(prefix, info->title_ui()); -+ html_source->AddLocalizedString(prefix + "Description", info->description_ui()); -+ html_source->AddLocalizedString(prefix + "Allowed", info->allowed_ui()); -+ html_source->AddLocalizedString(prefix + "Blocked", info->blocked_ui()); -+ html_source->AddLocalizedString(prefix + "AllowedExceptions", info->allowed_exceptions_ui()); -+ html_source->AddLocalizedString(prefix + "BlockedExceptions", info->blocked_exceptions_ui()); -+ html_source->AddLocalizedString(prefix + "MidSentence", info->mid_sentence_ui()); ++ if (info->title_ui()) ++ html_source->AddLocalizedString(prefix, info->title_ui()); ++ if (info->description_ui()) ++ html_source->AddLocalizedString(prefix + "Description", info->description_ui()); ++ if (info->allowed_ui()) ++ html_source->AddLocalizedString(prefix + "Allowed", info->allowed_ui()); ++ if (info->blocked_ui()) ++ html_source->AddLocalizedString(prefix + "Blocked", info->blocked_ui()); ++ if (info->ask_ui()) ++ html_source->AddLocalizedString(prefix + "Ask", info->ask_ui()); ++ if (info->allowed_exceptions_ui()) ++ html_source->AddLocalizedString(prefix + "AllowedExceptions", info->allowed_exceptions_ui()); ++ if (info->blocked_exceptions_ui()) ++ html_source->AddLocalizedString(prefix + "BlockedExceptions", info->blocked_exceptions_ui()); ++ if (info->mid_sentence_ui()) ++ html_source->AddLocalizedString(prefix + "MidSentence", info->mid_sentence_ui()); + + base::Value::Dict dict; + dict.Set("name", name); @@ -486,6 +1189,8 @@ diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provide + info->initial_default_value().GetInt() == (int)CONTENT_SETTING_ALLOW ? "allow" : + info->initial_default_value().GetInt() == (int)CONTENT_SETTING_BLOCK ? "block" : + "ask"); ++ dict.Set("allowed_ask", ++ content_setting->IsSettingValid(CONTENT_SETTING_ASK) ? "1" : "0"); + + std::string json_string; + base::JSONWriter::WriteWithOptions( @@ -584,6 +1289,169 @@ diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/b initialized = true; } +diff --git a/components/browser_ui/settings/android/BUILD.gn b/components/browser_ui/settings/android/BUILD.gn +--- a/components/browser_ui/settings/android/BUILD.gn ++++ b/components/browser_ui/settings/android/BUILD.gn +@@ -82,6 +82,7 @@ android_resources("java_resources") { + "java/res/layout/managed_disclaimer_preference_for_radio_groups.xml", + "java/res/layout/preference_chrome_image_view.xml", + "java/res/layout/preference_spinner.xml", ++ "java/res/layout/preference_spinner_single_widget.xml", + "java/res/layout/preference_spinner_single_line.xml", + "java/res/layout/preference_spinner_single_line_item.xml", + "java/res/layout/settings_action_bar_shadow.xml", +diff --git a/components/browser_ui/settings/android/java/res/layout/preference_spinner_single_widget.xml b/components/browser_ui/settings/android/java/res/layout/preference_spinner_single_widget.xml +new file mode 100644 +--- /dev/null ++++ b/components/browser_ui/settings/android/java/res/layout/preference_spinner_single_widget.xml +@@ -0,0 +1,92 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/SpinnerPreference.java b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/SpinnerPreference.java +--- a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/SpinnerPreference.java ++++ b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/SpinnerPreference.java +@@ -23,6 +23,7 @@ public class SpinnerPreference extends Preference { + private ArrayAdapter mAdapter; + private int mSelectedIndex; + private final boolean mSingleLine; ++ private boolean mIsWidget = false; + + /** Constructor for inflating from XML. */ + public SpinnerPreference(Context context, AttributeSet attrs) { +@@ -37,6 +38,19 @@ public class SpinnerPreference extends Preference { + } + } + ++ public SpinnerPreference(Context context, boolean singleLine) { ++ super(context, null); ++ mSingleLine = singleLine; ++ mIsWidget = true; ++ setLayoutResource(R.layout.preference_spinner_single_widget); ++ } ++ ++ @Override ++ protected void onClick() { ++ if (mIsWidget) ++ mSpinner.performClick(); ++ } ++ + /** + * Provides a list of arbitrary objects to be shown in the spinner. Visually, each option will + * be presented as its toString() text. Alternative to {@link #setAdapter(ArrayAdapter, int)}. +@@ -56,6 +70,12 @@ public class SpinnerPreference extends Preference { + mSelectedIndex = selectedIndex; + } + ++ public void setSelectedIndex(int selectedIndex) { ++ mSelectedIndex = selectedIndex; ++ if (mSpinner != null) ++ mSpinner.setSelection(mSelectedIndex); ++ } ++ + /** Returns the Spinner instance for introspection during tests. */ + public Spinner getSpinnerForTesting() { + return mSpinner; +@@ -88,6 +108,10 @@ public class SpinnerPreference extends Preference { + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + ++ if (mIsWidget) { ++ holder.setDividerAllowedAbove(true); ++ holder.setDividerAllowedBelow(true); ++ } + ((TextView) holder.findViewById(R.id.title)).setText(getTitle()); + CharSequence summary = getSummary(); + TextView summaryView = ((TextView) holder.findViewById(R.id.summary)); diff --git a/components/browser_ui/site_settings/android/BUILD.gn b/components/browser_ui/site_settings/android/BUILD.gn --- a/components/browser_ui/site_settings/android/BUILD.gn +++ b/components/browser_ui/site_settings/android/BUILD.gn @@ -645,7 +1513,7 @@ diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/c new file mode 100644 --- /dev/null +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BromiteCustomContentSetting.java -@@ -0,0 +1,139 @@ +@@ -0,0 +1,155 @@ +/* + This file is part of Bromite. + @@ -665,6 +1533,8 @@ new file mode 100644 + +package org.chromium.components.browser_ui.site_settings; + ++import android.content.Context; ++ +import org.chromium.components.browser_ui.site_settings.ContentSettingsResources; +import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory; +import org.chromium.components.content_settings.ContentSettingValues; @@ -721,6 +1591,20 @@ new file mode 100644 + return mDefaultDisabledValue; + } + ++ public Preference createWebSitePreference(Context context, ++ @ContentSettingValues @Nullable Integer value) { ++ return null; ++ } ++ ++ public boolean setWebSitePreferenceValue(Preference preference, ++ @ContentSettingValues @Nullable Integer value) { ++ return false; ++ } ++ ++ public Integer getWebSitePreferenceValue(Object newValue) { ++ return null; ++ } ++ + public String getPreferenceKey() { + return mPreferenceKey; + } @@ -789,7 +1673,7 @@ diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/c new file mode 100644 --- /dev/null +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BromiteCustomContentSettingImpl.java -@@ -0,0 +1,307 @@ +@@ -0,0 +1,409 @@ +/* + This file is part of Bromite. + @@ -812,6 +1696,8 @@ new file mode 100644 +import android.app.Activity; +import android.content.Context; + ++import org.chromium.base.Log; ++import org.chromium.components.browser_ui.settings.SpinnerPreference; +import org.chromium.components.browser_ui.site_settings.ContentSettingsResources; +import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory; +import org.chromium.components.content_settings.ContentSettingValues; @@ -832,6 +1718,27 @@ new file mode 100644 +public abstract class BromiteCustomContentSettingImpl + extends BromiteCustomContentSettingImplBase { + ++ static class ContentSettingsSpinnerOption { ++ private @ContentSettingValues int mValue; ++ private String mDescription; ++ ++ public ContentSettingsSpinnerOption( ++ @ContentSettingValues int value, ++ String description) { ++ mValue = value; ++ mDescription = description; ++ } ++ ++ public @ContentSettingValues int getValue() { ++ return mValue; ++ } ++ ++ @Override ++ public String toString() { ++ return mDescription; ++ } ++ } ++ + public static SiteSettingsCategory createFromType( + BrowserContextHandle browserContextHandle, @SiteSettingsCategory.Type int type) { + for (BromiteCustomContentSetting cs : mItemList) { @@ -855,6 +1762,85 @@ new file mode 100644 + return null; + } + ++ public static Preference createWebSitePreference( ++ @ContentSettingsType int type, ++ Context context, ++ @ContentSettingValues @Nullable Integer value) { ++ BromiteCustomContentSetting cs = getContentSetting(type); ++ if (cs != null) { ++ Preference pref = cs.createWebSitePreference(context, value); ++ if (pref != null) return pref; ++ ++ if (cs.requiresTriStateContentSetting()) { ++ int[] descriptions = cs.getTriStateSettingDescriptionIDs(); ++ ++ List options = new ArrayList<>(); ++ options.add(new ContentSettingsSpinnerOption( ++ ContentSettingValues.ALLOW, ++ context.getText(descriptions[0]).toString())); ++ options.add(new ContentSettingsSpinnerOption( ++ ContentSettingValues.ASK, ++ context.getText(descriptions[1]).toString())); ++ options.add(new ContentSettingsSpinnerOption( ++ ContentSettingValues.BLOCK, ++ context.getText(descriptions[2]).toString())); ++ ++ SpinnerPreference spinner = new SpinnerPreference(context, true); ++ spinner.setOptions(options.toArray(), ++ GetContentSettingValuesIndex(value)); ++ return spinner; ++ } ++ } ++ return null; ++ } ++ ++ private static int GetContentSettingValuesIndex( ++ @ContentSettingValues @Nullable Integer value) { ++ if (value == null) ++ return 0; ++ else if (value == ContentSettingValues.ALLOW) ++ return 0; ++ else if (value == ContentSettingValues.ASK) ++ return 1; ++ else if (value == ContentSettingValues.BLOCK) ++ return 2; ++ return 0; ++ } ++ ++ public static void setWebSitePreferenceValue( ++ @ContentSettingsType int type, ++ Preference preference, ++ @ContentSettingValues @Nullable Integer value) { ++ BromiteCustomContentSetting cs = getContentSetting(type); ++ if (cs != null) { ++ if (cs.setWebSitePreferenceValue(preference, value)) ++ return; ++ if (cs.requiresTriStateContentSetting() && value != null && ++ preference instanceof SpinnerPreference) { ++ ((SpinnerPreference)preference).setSelectedIndex( ++ GetContentSettingValuesIndex(value)); ++ return; ++ } ++ } ++ return; ++ } ++ ++ public static Integer getWebSitePreferenceValue( ++ @ContentSettingsType int type, ++ Object newValue) { ++ BromiteCustomContentSetting cs = getContentSetting(type); ++ if (cs != null) { ++ Integer permission = cs.getWebSitePreferenceValue(newValue); ++ if (permission != null) return permission; ++ ++ if (cs.requiresTriStateContentSetting() && ++ newValue instanceof ContentSettingsSpinnerOption) { ++ return ((ContentSettingsSpinnerOption)newValue).getValue(); ++ } ++ } ++ return null; ++ } ++ + public static @Nullable String getPreferenceKey(@SiteSettingsCategory.Type int type) { + for (BromiteCustomContentSetting cs : mItemList) { + if (type == cs.getSiteSettingsCategory()) { @@ -1343,17 +2329,31 @@ diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/c } } -@@ -544,7 +545,8 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment +@@ -544,8 +545,21 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment private void setupContentSettingsPreferences() { mMaxPermissionOrder = findPreference(PREF_PERMISSIONS_HEADER).getOrder(); - for (@ContentSettingsType int type : SiteSettingsUtil.SETTINGS_ORDER) { +- Preference preference = new ChromeSwitchPreference(getStyledContext()); + List order = BromiteCustomContentSettingImpl.getSettingsOrder(); + for (@ContentSettingsType int type : order) { - Preference preference = new ChromeSwitchPreference(getStyledContext()); ++ @ContentSettingValues @Nullable Integer value = ++ mSite.getContentSetting( ++ getSiteSettingsDelegate().getBrowserContextHandle(), type); ++ if (value == null) { ++ value = WebsitePreferenceBridge.getDefaultContentSetting( ++ getSiteSettingsDelegate().getBrowserContextHandle(), type); ++ } ++ Preference preference = ++ BromiteCustomContentSettingImpl ++ .createWebSitePreference(type, getStyledContext(), value); ++ if (preference == null) { ++ preference = new ChromeSwitchPreference(getStyledContext()); ++ } preference.setKey(getPreferenceKey(type)); -@@ -1085,15 +1087,23 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment + if (type == ContentSettingsType.ADS) { +@@ -1085,20 +1099,32 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment Preference preference, @ContentSettingValues @Nullable Integer value, boolean isEmbargoed) { @@ -1369,9 +2369,14 @@ diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/c + } setUpPreferenceCommon(preference, value); - ChromeSwitchPreference switchPreference = (ChromeSwitchPreference) preference; +- ChromeSwitchPreference switchPreference = (ChromeSwitchPreference) preference; - switchPreference.setChecked(value == ContentSettingValues.ALLOW); -+ switchPreference.setChecked(value != ContentSettingValues.BLOCK); ++ Preference switchPreference = preference; ++ if (preference instanceof ChromeSwitchPreference) { ++ ((ChromeSwitchPreference)switchPreference).setChecked(value != ContentSettingValues.BLOCK); ++ } else { ++ BromiteCustomContentSettingImpl.setWebSitePreferenceValue(content_type, preference, value); ++ } switchPreference.setSummary( isEmbargoed ? getString(R.string.automatically_blocked) @@ -1380,7 +2385,14 @@ diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/c switchPreference.setOnPreferenceChangeListener(this); @ContentSettingsType int contentType = getContentSettingsTypeFromPreferenceKey(preference.getKey()); -@@ -1256,7 +1266,7 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment +- if (contentType == mHighlightedPermission) { +- switchPreference.setBackgroundColor(mHighlightColor); ++ if (preference instanceof ChromeSwitchPreference && contentType == mHighlightedPermission) { ++ ((ChromeSwitchPreference)switchPreference).setBackgroundColor(mHighlightColor); + } + if (isSessionPermission(contentType)) { + switchPreference.setSummary(switchPreference.getSummary() + " " + +@@ -1256,7 +1282,7 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment public @ContentSettingsType int getContentSettingsTypeFromPreferenceKey(String preferenceKey) { if (mPreferenceMap == null) { mPreferenceMap = new HashMap<>(); @@ -1389,7 +2401,18 @@ diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/c String key = getPreferenceKey(type); if (key != null) { mPreferenceMap.put(key, type); -@@ -1297,7 +1307,7 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment +@@ -1293,11 +1319,17 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment + permission = + (Boolean) newValue ? ContentSettingValues.ALLOW : ContentSettingValues.BLOCK; + } else { +- permission = (Integer) newValue; ++ Integer newPermission = ++ BromiteCustomContentSettingImpl ++ .getWebSitePreferenceValue(type, newValue); ++ if (newPermission != null) ++ permission = newPermission; ++ else ++ permission = (Integer) newValue; } mSite.setContentSetting(browserContextHandle, type, permission); @@ -1398,7 +2421,7 @@ diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/c preference.setIcon(getContentSettingsIcon(type, permission)); if (mWebsiteSettingsObserver != null) { -@@ -1325,7 +1335,7 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment +@@ -1325,7 +1357,7 @@ public class SingleWebsiteSettings extends BaseSiteSettingsFragment // TODO(mvanouwerkerk): Refactor this class so that it does not depend on the screen state // for its logic. This class should maintain its own data model, and only update the screen // after a change is made. @@ -1802,7 +2825,7 @@ diff --git a/components/content_settings/core/browser/content_settings_utils.cc diff --git a/components/content_settings/core/browser/website_settings_info.h b/components/content_settings/core/browser/website_settings_info.h --- a/components/content_settings/core/browser/website_settings_info.h +++ b/components/content_settings/core/browser/website_settings_info.h -@@ -132,6 +132,30 @@ class WebsiteSettingsInfo { +@@ -132,6 +132,32 @@ class WebsiteSettingsInfo { ScopingType scoping_type() const { return scoping_type_; } IncognitoBehavior incognito_behavior() const { return incognito_behavior_; } @@ -1814,6 +2837,7 @@ diff --git a/components/content_settings/core/browser/website_settings_info.h b/ + int description_ui() const { return description_ui_; } + int allowed_ui() const { return allowed_ui_; } + int blocked_ui() const { return blocked_ui_; } ++ int ask_ui() const { return ask_ui_; } + int allowed_exceptions_ui() const { return allowed_exceptions_ui_; } + int blocked_exceptions_ui() const { return blocked_exceptions_ui_; } + int mid_sentence_ui() const { return mid_sentence_ui_; } @@ -1826,6 +2850,7 @@ diff --git a/components/content_settings/core/browser/website_settings_info.h b/ + WebsiteSettingsInfo& set_description_ui(int value) { description_ui_ = value; return *this; } + WebsiteSettingsInfo& set_allowed_ui(int value) { allowed_ui_ = value; return *this; } + WebsiteSettingsInfo& set_blocked_ui(int value) { blocked_ui_ = value; return *this; } ++ WebsiteSettingsInfo& set_ask_ui(int value) { ask_ui_ = value; return *this; } + WebsiteSettingsInfo& set_allowed_exceptions_ui(int value) { allowed_exceptions_ui_ = value; return *this; } + WebsiteSettingsInfo& set_blocked_exceptions_ui(int value) { blocked_exceptions_ui_ = value; return *this; } + WebsiteSettingsInfo& set_mid_sentence_ui(int value) { mid_sentence_ui_ = value; return *this; } @@ -1833,7 +2858,7 @@ diff --git a/components/content_settings/core/browser/website_settings_info.h b/ private: const ContentSettingsType type_; const std::string name_; -@@ -143,6 +167,17 @@ class WebsiteSettingsInfo { +@@ -143,6 +169,18 @@ class WebsiteSettingsInfo { const LossyStatus lossy_status_; const ScopingType scoping_type_; const IncognitoBehavior incognito_behavior_; @@ -1845,6 +2870,7 @@ diff --git a/components/content_settings/core/browser/website_settings_info.h b/ + int description_ui_ = 0; + int allowed_ui_ = 0; + int blocked_ui_ = 0; ++ int ask_ui_ = 0; + int allowed_exceptions_ui_ = 0; + int blocked_exceptions_ui_ = 0; + int mid_sentence_ui_ = 0;