From: uazo Date: Wed, 30 Sep 2020 07:40:01 +0000 Subject: Timezone customization Allow specifying a custom timezone, or using a random one. See also: https://github.com/bromite/bromite/wiki/TimezoneOverride 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 --- .../ChromeSiteSettingsDelegate.java | 16 ++ .../browser_ui/site_settings/android/BUILD.gn | 3 + .../res/layout/time_zone_select_dialog.xml | 36 ++++ ...ezoneoverride_site_settings_preference.xml | 68 ++++++ .../res/xml/site_settings_preferences.xml | 4 + .../java/res/xml/website_preferences.xml | 10 + .../ContentSettingsResources.java | 33 +++ .../site_settings/SingleCategorySettings.java | 58 +++++- .../site_settings/SingleWebsiteSettings.java | 8 +- .../site_settings/SiteSettings.java | 2 +- .../site_settings/SiteSettingsCategory.java | 8 +- .../site_settings/SiteSettingsDelegate.java | 2 + ...imezoneOverrideSiteSettingsPreference.java | 193 ++++++++++++++++++ .../browser_ui/site_settings/Website.java | 11 + .../WebsitePermissionsFetcher.java | 2 + .../WebsitePreferenceBridge.java | 12 ++ .../android/website_preference_bridge.cc | 16 ++ .../strings/android/site_settings.grdp | 35 ++++ .../browser/content_settings_pref_provider.cc | 16 ++ .../browser/content_settings_pref_provider.h | 4 + .../core/browser/content_settings_registry.cc | 12 ++ .../core/browser/content_settings_utils.cc | 7 + .../core/browser/host_content_settings_map.cc | 8 + .../core/browser/host_content_settings_map.h | 3 + .../core/common/content_settings.cc | 4 +- .../core/common/content_settings.h | 2 + .../core/common/content_settings.mojom | 2 + .../common/content_settings_mojom_traits.cc | 4 +- .../common/content_settings_mojom_traits.h | 10 + .../core/common/content_settings_types.h | 3 + .../core/common/pref_names.cc | 3 + .../content_settings/core/common/pref_names.h | 2 + .../renderer/content_settings_agent_impl.cc | 83 ++++++++ .../renderer/content_settings_agent_impl.h | 11 + .../WebLayerSiteSettingsDelegate.java | 3 + 35 files changed, 684 insertions(+), 10 deletions(-) create mode 100755 components/browser_ui/site_settings/android/java/res/layout/time_zone_select_dialog.xml create mode 100755 components/browser_ui/site_settings/android/java/res/layout/timezoneoverride_site_settings_preference.xml create mode 100755 components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/TimezoneOverrideSiteSettingsPreference.java diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java --- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java @@ -46,6 +46,10 @@ import org.chromium.url.GURL; import java.util.Set; +import android.content.Intent; +import android.provider.Browser; +import android.net.Uri; + /** * A SiteSettingsDelegate instance that contains Chrome-specific Site Settings logic. */ @@ -265,6 +269,18 @@ public class ChromeSiteSettingsDelegate implements SiteSettingsDelegate { return PrivacySandboxBridge.getFirstPartySetOwner(memberOrigin); } + // open wiki page for documentation about the timezone override feature + @Override + public void launchTimeZoneOverrideHelpAndFeedbackActivity(Activity currentActivity) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/bromite/bromite/wiki/TimezoneOverride")); + // Let Chromium know that this intent is from Chromium, so that it does not close the app when + // the user presses 'back' button. + intent.putExtra(Browser.EXTRA_APPLICATION_ID, currentActivity.getPackageName()); + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); + intent.setPackage(currentActivity.getPackageName()); + currentActivity.startActivity(intent); + } + @Override public boolean canLaunchClearBrowsingDataDialog() { return true; 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 @@ -87,6 +87,7 @@ android_library("java") { "java/src/org/chromium/components/browser_ui/site_settings/WebsitePreference.java", "java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java", "java/src/org/chromium/components/browser_ui/site_settings/WebsiteRowPreference.java", + "java/src/org/chromium/components/browser_ui/site_settings/TimezoneOverrideSiteSettingsPreference.java" ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] resources_package = "org.chromium.components.browser_ui.site_settings" @@ -226,6 +227,8 @@ android_resources("java_resources") { "java/res/xml/site_settings_preferences.xml", "java/res/xml/site_settings_preferences_with_categories.xml", "java/res/xml/website_preferences.xml", + "java/res/layout/timezoneoverride_site_settings_preference.xml", + "java/res/layout/time_zone_select_dialog.xml", ] deps = [ diff --git a/components/browser_ui/site_settings/android/java/res/layout/time_zone_select_dialog.xml b/components/browser_ui/site_settings/android/java/res/layout/time_zone_select_dialog.xml new file mode 100755 --- /dev/null +++ b/components/browser_ui/site_settings/android/java/res/layout/time_zone_select_dialog.xml @@ -0,0 +1,36 @@ + + + + + + + + + + \ No newline at end of file diff --git a/components/browser_ui/site_settings/android/java/res/layout/timezoneoverride_site_settings_preference.xml b/components/browser_ui/site_settings/android/java/res/layout/timezoneoverride_site_settings_preference.xml new file mode 100755 --- /dev/null +++ b/components/browser_ui/site_settings/android/java/res/layout/timezoneoverride_site_settings_preference.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + diff --git a/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences.xml b/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences.xml --- a/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences.xml +++ b/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences.xml @@ -47,6 +47,10 @@ Also add new settings to site_settings_preferences_with_categories.xml! + + + + + + + + + mWebsites; // Whether tri-state ContentSetting is required. - private @GlobalToggleLayout int mGlobalToggleLayout = GlobalToggleLayout.BINARY_TOGGLE; + private @GlobalToggleLayout int mGlobalToggleLayout = GlobalToggleLayout.BINARY_TOGGLE; ADD TIMEZONE // The "notifications_quiet_ui" preference to allow hiding/showing it. private ChromeBaseCheckBoxPreference mNotificationsQuietUiPref; // The "desktop_site_peripheral" preference to allow hiding/showing it. @@ -184,6 +188,7 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment public static final String TRI_STATE_TOGGLE_KEY = "tri_state_toggle"; public static final String TRI_STATE_COOKIE_TOGGLE = "tri_state_cookie_toggle"; public static final String FOUR_STATE_COOKIE_TOGGLE_KEY = "four_state_cookie_toggle"; + public static final String TIMEOVERRIDE_STATE_TOGGLE_KEY = "timeoverride_state_toggle"; // Keys for category-specific preferences (toggle, link, button etc.), dynamically shown. public static final String NOTIFICATIONS_VIBRATE_TOGGLE_KEY = "notifications_vibrate"; @@ -193,6 +198,7 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment public static final String EXPLAIN_PROTECTED_MEDIA_KEY = "protected_content_learn_more"; public static final String ADD_EXCEPTION_KEY = "add_exception"; public static final String INFO_TEXT_KEY = "info_text"; + public static final String TIMEOVERRIDE_INFO_TEXT = "timeoverride_info_text"; // Keys for Allowed/Blocked preference groups/headers. public static final String ALLOWED_GROUP = "allowed_group"; @@ -285,7 +291,11 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment Integer contentSetting = website.site().getContentSetting( browserContextHandle, mCategory.getContentSettingsType()); if (contentSetting != null) { - return ContentSettingValues.BLOCK == contentSetting; + if (mCategory.getContentSettingsType() == SiteSettingsCategory.Type.TIMEZONE_OVERRIDE) { + return ContentSettingValues.ALLOW != contentSetting; + } else { + return ContentSettingValues.BLOCK == contentSetting; + } } return false; } @@ -463,7 +473,8 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment if (queryHasChanged) getInfoForOrigins(); }); - if (getSiteSettingsDelegate().isHelpAndFeedbackEnabled()) { + if (getSiteSettingsDelegate().isHelpAndFeedbackEnabled() || + mCategory.getType() == SiteSettingsCategory.Type.TIMEZONE_OVERRIDE) { MenuItem help = menu.add( Menu.NONE, R.id.menu_id_site_settings_help, Menu.NONE, R.string.menu_help); help.setIcon(VectorDrawableCompat.create( @@ -474,7 +485,10 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.menu_id_site_settings_help) { - if (mCategory.getType() == SiteSettingsCategory.Type.PROTECTED_MEDIA) { + if (mCategory.getType() == SiteSettingsCategory.Type.TIMEZONE_OVERRIDE) { + getSiteSettingsDelegate() + .launchTimeZoneOverrideHelpAndFeedbackActivity(getActivity()); + } else if (mCategory.getType() == SiteSettingsCategory.Type.PROTECTED_MEDIA) { getSiteSettingsDelegate().launchProtectedContentHelpAndFeedbackActivity( getActivity()); } else { @@ -576,6 +590,12 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment WebsitePreferenceBridge.setDefaultContentSetting( browserContextHandle, mCategory.getContentSettingsType(), setting); getInfoForOrigins(); + } else if (TIMEOVERRIDE_STATE_TOGGLE_KEY.equals(preference.getKey())) { + @ContentSettingValues + int setting = (int) newValue; + WebsitePreferenceBridge.setDefaultContentSetting( + browserContextHandle, ContentSettingsType.TIMEZONE_OVERRIDE, setting); + getInfoForOrigins(); } else if (FOUR_STATE_COOKIE_TOGGLE_KEY.equals(preference.getKey())) { setCookieSettingsPreference((CookieSettingsState) newValue); getInfoForOrigins(); @@ -739,6 +759,12 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment ? R.string.website_settings_blocked_group_heading_request_desktop_site : R.string.website_settings_allowed_group_heading_request_desktop_site; break; + case SiteSettingsCategory.Type.TIMEZONE_OVERRIDE: + resource = WebsitePreferenceBridge.isCategoryEnabled( + browserContextHandle, ContentSettingsType.TIMEZONE_OVERRIDE) + ? R.string.website_settings_category_timezone_override_allowed + : R.string.website_settings_category_timezone_override_blocked; + break; } assert resource > 0; return getString(resource); @@ -861,6 +887,9 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment default: break; } + if (mCategory.getType() == SiteSettingsCategory.Type.TIMEZONE_OVERRIDE) { + allowSpecifyingExceptions = true; + } if (allowSpecifyingExceptions) { getPreferenceScreen().addPreference(new AddExceptionPreference(getStyledContext(), ADD_EXCEPTION_KEY, getAddExceptionDialogMessage(), mCategory, this)); @@ -1182,6 +1211,18 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment mListView.setFocusable(true); } + TimezoneOverrideSiteSettingsPreference timeOverrideStatePreference = + (TimezoneOverrideSiteSettingsPreference) screen.findPreference( + TIMEOVERRIDE_STATE_TOGGLE_KEY); + if (mCategory.getType() == SiteSettingsCategory.Type.TIMEZONE_OVERRIDE) { + screen.removePreference(triStateToggle); + configureTimeOverrideStateToggle(timeOverrideStatePreference); + } + else { + screen.removePreference(timeOverrideStatePreference); + configureTriStateToggle(triStateToggle, contentType); + } + // When this menu opens, make sure the Blocked list is collapsed. if (!mGroupByAllowBlock) { mBlockListExpanded = false; @@ -1269,6 +1310,15 @@ public class SingleCategorySettings extends SiteSettingsPreferenceFragment triStateToggle.initialize(setting, descriptionIds); } + private void configureTimeOverrideStateToggle( + TimezoneOverrideSiteSettingsPreference timeOverrideStateToggle) { + timeOverrideStateToggle.setOnPreferenceChangeListener(this); + @ContentSettingValues + int setting = WebsitePreferenceBridge.getDefaultContentSetting( + getSiteSettingsDelegate().getBrowserContextHandle(), ContentSettingsType.TIMEZONE_OVERRIDE); + timeOverrideStateToggle.initialize(setting, getSiteSettingsDelegate().getBrowserContextHandle()); + } + private void configureBinaryToggle(ChromeSwitchPreference binaryToggle, int contentType) { binaryToggle.setOnPreferenceChangeListener(this); binaryToggle.setTitle( 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 @@ -138,6 +138,8 @@ public class SingleWebsiteSettings extends SiteSettingsPreferenceFragment return "popup_permission_list"; case ContentSettingsType.SOUND: return "sound_permission_list"; + case ContentSettingsType.TIMEZONE_OVERRIDE: + return "timezone_override_permission_list"; case ContentSettingsType.AR: return "ar_permission_list"; case ContentSettingsType.MEDIASTREAM_CAMERA: @@ -938,11 +940,13 @@ public class SingleWebsiteSettings extends SiteSettingsPreferenceFragment if (value == null) return; setUpPreferenceCommon(preference, value); + int content_type = getContentSettingsTypeFromPreferenceKey(preference.getKey()); + ChromeSwitchPreference switchPreference = (ChromeSwitchPreference) preference; switchPreference.setChecked(value == ContentSettingValues.ALLOW); switchPreference.setSummary(isEmbargoed ? getString(R.string.automatically_blocked) - : getString(ContentSettingsResources.getCategorySummary(value))); + : getString(ContentSettingsResources.getCategorySummary(content_type, value))); switchPreference.setOnPreferenceChangeListener(this); @ContentSettingsType int contentType = getContentSettingsTypeFromPreferenceKey(preference.getKey()); @@ -1142,7 +1146,7 @@ public class SingleWebsiteSettings extends SiteSettingsPreferenceFragment } mSite.setContentSetting(browserContextHandle, type, permission); - preference.setSummary(getString(ContentSettingsResources.getCategorySummary(permission))); + preference.setSummary(getString(ContentSettingsResources.getCategorySummary(type, permission))); preference.setIcon(getContentSettingsIcon(type, permission)); if (mWebsiteSettingsObserver != null) { diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettings.java --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettings.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettings.java @@ -132,7 +132,7 @@ public class SiteSettings } else if (Type.AUTO_DARK_WEB_CONTENT == prefCategory) { p.setSummary(ContentSettingsResources.getAutoDarkWebContentListSummary(checked)); } else if (requiresTriStateSetting) { - p.setSummary(ContentSettingsResources.getCategorySummary(setting)); + p.setSummary(ContentSettingsResources.getCategorySummary(contentType, setting)); } else { p.setSummary(ContentSettingsResources.getCategorySummary(contentType, checked)); } diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsCategory.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsCategory.java --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsCategory.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsCategory.java @@ -47,6 +47,7 @@ public class SiteSettingsCategory { Type.PROTECTED_MEDIA, Type.SENSORS, Type.SOUND, Type.USB, Type.VIRTUAL_REALITY, Type.USE_STORAGE, Type.AUTO_DARK_WEB_CONTENT, Type.REQUEST_DESKTOP_SITE, Type.FEDERATED_IDENTITY_API, Type.THIRD_PARTY_COOKIES, Type.SITE_DATA, + Type.TIMEZONE_OVERRIDE, Type.NUM_ENTRIES}) @Retention(RetentionPolicy.SOURCE) public @interface Type { @@ -80,10 +81,11 @@ public class SiteSettingsCategory { int FEDERATED_IDENTITY_API = 25; int THIRD_PARTY_COOKIES = 26; int SITE_DATA = 27; + int TIMEZONE_OVERRIDE = 28; /** * Number of handled categories used for calculating array sizes. */ - int NUM_ENTRIES = 28; + int NUM_ENTRIES = 29; } private final BrowserContextHandle mBrowserContextHandle; @@ -210,6 +212,8 @@ public class SiteSettingsCategory { return ContentSettingsType.USB_GUARD; case Type.VIRTUAL_REALITY: return ContentSettingsType.VR; + case Type.TIMEZONE_OVERRIDE: + return ContentSettingsType.TIMEZONE_OVERRIDE; case Type.ALL_SITES: case Type.USE_STORAGE: return ContentSettingsType.DEFAULT; // Conversion unavailable. @@ -295,6 +299,8 @@ public class SiteSettingsCategory { return "site_data"; case Type.THIRD_PARTY_COOKIES: return "third_party_cookies"; + case Type.TIMEZONE_OVERRIDE: + return "timezone_override"; default: assert false; return ""; diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java @@ -163,6 +163,8 @@ public interface SiteSettingsDelegate { */ String getFirstPartySetOwner(String memberOrigin); + void launchTimeZoneOverrideHelpAndFeedbackActivity(Activity currentActivity); + /** * Returns whether the current implementation of the delegate is able to launch the Clear * Browsing Data dialog in Settings. diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/TimezoneOverrideSiteSettingsPreference.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/TimezoneOverrideSiteSettingsPreference.java new file mode 100755 --- /dev/null +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/TimezoneOverrideSiteSettingsPreference.java @@ -0,0 +1,193 @@ +/* + This file is part of Bromite. + + Bromite is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bromite is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bromite. If not, see . +*/ + +package org.chromium.components.browser_ui.site_settings; + +import org.chromium.base.Log; +import android.content.Context; +import android.content.Intent; +import android.content.DialogInterface; +import android.view.View; +import android.widget.RadioGroup; +import android.widget.Button; +import android.widget.TextView; +import android.util.AttributeSet; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.view.LayoutInflater; +import android.widget.AdapterView; +import android.graphics.Color; + +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; +import androidx.appcompat.app.AlertDialog; + +import org.chromium.content_public.browser.BrowserContextHandle; +import org.chromium.components.content_settings.ContentSettingValues; +import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge; +import org.chromium.components.browser_ui.widget.RadioButtonWithDescription; +import org.chromium.components.browser_ui.widget.RadioButtonWithEditText; +import org.chromium.components.browser_ui.widget.TintedDrawable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.TimeZone; + +/** + * TimezoneOverride Preference for SiteSettings. + */ +public class TimezoneOverrideSiteSettingsPreference + extends Preference implements RadioGroup.OnCheckedChangeListener, + RadioButtonWithEditText.OnTextChangeListener { + private @ContentSettingValues int mSetting = ContentSettingValues.DEFAULT; + private RadioButtonWithDescription mAllowed; + private RadioButtonWithEditText mAsk; + private RadioButtonWithDescription mBlocked; + private RadioGroup mRadioGroup; + private TextView mSelectButton; + + private String currentSelected; + + private BrowserContextHandle mBrowserContextHandle; + + public TimezoneOverrideSiteSettingsPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + setLayoutResource(R.layout.timezoneoverride_site_settings_preference); + setSelectable(false); + } + + public void initialize(@ContentSettingValues int setting, BrowserContextHandle browserContextHandle) { + mSetting = setting; + mBrowserContextHandle = browserContextHandle; + } + + public @ContentSettingValues int getCheckedSetting() { + return mSetting; + } + + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + if (mAllowed.isChecked()) { + mSetting = ContentSettingValues.ALLOW; + } else if (mAsk.isChecked()) { + mSetting = ContentSettingValues.ASK; + } else if (mBlocked.isChecked()) { + mSetting = ContentSettingValues.BLOCK; + } + + callChangeListener(mSetting); + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + + mAllowed = (RadioButtonWithDescription) holder.findViewById(R.id.allowed); + mAsk = (RadioButtonWithEditText) holder.findViewById(R.id.ask); + mBlocked = (RadioButtonWithDescription) holder.findViewById(R.id.blocked); + mRadioGroup = (RadioGroup) holder.findViewById(R.id.radio_button_layout); + mRadioGroup.setOnCheckedChangeListener(this); + + mAsk.setPrimaryText(WebsitePreferenceBridge.getCustomTimezone(mBrowserContextHandle)); + mAsk.addTextChangeListener(this); + + ListView listView = (ListView)holder.findViewById(R.id.listView); + + mSelectButton = (TextView) holder.findViewById(R.id.select_button); + mSelectButton.setOnClickListener(view -> { + showSelectTimeZoneDialog(); + }); + + RadioButtonWithDescription radioButton = findRadioButton(mSetting); + if (radioButton != null) radioButton.setChecked(true); + } + + private RadioButtonWithDescription findRadioButton(@ContentSettingValues int setting) { + if (setting == ContentSettingValues.ALLOW) { + return mAllowed; + } else if (setting == ContentSettingValues.ASK) { + return mAsk; + } else if (setting == ContentSettingValues.BLOCK) { + return mBlocked; + } else { + return null; + } + } + + public void onTextChanged(CharSequence newText) { + WebsitePreferenceBridge.setCustomTimezone(mBrowserContextHandle, newText.toString()); + } + + private void showSelectTimeZoneDialog() { + LayoutInflater inflater = + (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflater.inflate(R.layout.time_zone_select_dialog, null); + + ListView listView = view.findViewById(R.id.listView); + ArrayList timezones = new ArrayList<>(Arrays.asList(TimeZone.getAvailableIDs())); + ArrayAdapter adapter = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, android.R.id.text1, timezones); + listView.setAdapter(adapter); + + currentSelected = String.valueOf(mAsk.getPrimaryText()); + listView.post(new Runnable() + { + public void run() + { + for (int j = 0; j < timezones.size(); j++) { + if (currentSelected.equals(timezones.get(j))) { + listView.requestFocusFromTouch(); + listView.setSelection(j); + adapter.notifyDataSetChanged(); + break; + } + } + } + }); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + currentSelected = timezones.get(i); + listView.setSelected(true); + } + }); + + DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int button) { + if (button == AlertDialog.BUTTON_POSITIVE) { + mAsk.setPrimaryText(currentSelected); + } else { + dialog.dismiss(); + } + } + }; + + AlertDialog.Builder alert = + new AlertDialog.Builder(getContext(), R.style.ThemeOverlay_BrowserUI_AlertDialog); + AlertDialog alertDialog = + alert.setTitle(R.string.website_settings_select_dialog_title) + .setView(view) + .setPositiveButton( + R.string.website_settings_select_dialog_button, onClickListener) + .setNegativeButton(R.string.cancel, onClickListener) + .create(); + alertDialog.getDelegate().setHandleNativeActionModesEnabled(false); + alertDialog.show(); + } +} diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java @@ -243,6 +243,17 @@ public final class Website implements WebsiteEntry { } else { RecordUserAction.record("SoundContentSetting.UnmuteBy.SiteSettings"); } + } else if (type == ContentSettingsType.TIMEZONE_OVERRIDE) { + // It is possible to set the permission without having an existing exception, + // because we can show the ALLOW state even when this permission is set to the + // default. In that case, just set an exception now to ALLOW to enable changing the + // permission. + if (exception == null) { + exception = new ContentSettingException( + ContentSettingsType.TIMEZONE_OVERRIDE, getAddress().getHost(), value, "", + /*isEmbargoed=*/false); + setContentSettingException(type, exception); + } } // We want to call setContentSetting even after explicitly setting // mContentSettingException above because this will trigger the actual change diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java @@ -73,6 +73,7 @@ public class WebsitePermissionsFetcher { case ContentSettingsType.POPUPS: case ContentSettingsType.REQUEST_DESKTOP_SITE: case ContentSettingsType.SOUND: + case ContentSettingsType.TIMEZONE_OVERRIDE: return WebsitePermissionsType.CONTENT_SETTING_EXCEPTION; case ContentSettingsType.AR: case ContentSettingsType.CLIPBOARD_READ_WRITE: @@ -210,6 +211,7 @@ public class WebsitePermissionsFetcher { for (@ContentSettingsType int type = 0; type < ContentSettingsType.NUM_TYPES; type++) { addFetcherForContentSettingsType(queue, type); } + queue.add(new ExceptionInfoFetcher(ContentSettingsType.TIMEZONE_OVERRIDE)); } /** diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java @@ -243,6 +243,8 @@ public class WebsitePreferenceBridge { switch (contentSettingsType) { case ContentSettingsType.PROTECTED_MEDIA_IDENTIFIER: return true; + case ContentSettingsType.TIMEZONE_OVERRIDE: + return true; default: return false; } @@ -383,6 +385,14 @@ public class WebsitePreferenceBridge { return WebsitePreferenceBridgeJni.get().toHostOnlyPattern(pattern); } + public static String getCustomTimezone(BrowserContextHandle browserContextHandle) { + return WebsitePreferenceBridgeJni.get().getCustomTimezone(browserContextHandle); + } + + public static void setCustomTimezone(BrowserContextHandle browserContextHandle, String custom_timezone) { + WebsitePreferenceBridgeJni.get().setCustomTimezone(browserContextHandle, custom_timezone); + } + @NativeMethods public interface Natives { boolean isNotificationEmbargoedForOrigin( @@ -447,5 +457,7 @@ public class WebsitePreferenceBridge { boolean getLocationAllowedByPolicy(BrowserContextHandle browserContextHandle); String toDomainWildcardPattern(String pattern); String toHostOnlyPattern(String pattern); + String getCustomTimezone(BrowserContextHandle browserContextHandle); + void setCustomTimezone(BrowserContextHandle browserContextHandle, String custom_timezone); } } 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 @@ -1016,3 +1016,19 @@ JNI_WebsitePreferenceBridge_ToHostOnlyPattern( ContentSettingsPattern::FromString(pattern_string)); return ConvertUTF8ToJavaString(env, host_only_pattern.ToString()); } + +static void JNI_WebsitePreferenceBridge_SetCustomTimezone( + JNIEnv* env, + const JavaParamRef& jbrowser_context_handle, + const JavaParamRef& custom_timezone) { + std::string new_timezone = ConvertJavaStringToUTF8(env, custom_timezone); + GetHostContentSettingsMap(jbrowser_context_handle)->SetTimezoneOverrideValue(new_timezone); +} + +static base::android::ScopedJavaLocalRef JNI_WebsitePreferenceBridge_GetCustomTimezone( + JNIEnv* env, + const JavaParamRef& jbrowser_context_handle) { + std::string custom_timezone; + GetHostContentSettingsMap(jbrowser_context_handle)->GetTimezoneOverrideValue(custom_timezone); + return ConvertUTF8ToJavaString(env, custom_timezone); +} diff --git a/components/browser_ui/strings/android/site_settings.grdp b/components/browser_ui/strings/android/site_settings.grdp --- a/components/browser_ui/strings/android/site_settings.grdp +++ b/components/browser_ui/strings/android/site_settings.grdp @@ -103,6 +103,9 @@ Dark theme for sites + + Timezone override + Desktop site @@ -685,6 +688,38 @@ Block sites from playing protected content + + + Override timezone with a custom or random one, or use the system timezone + + + None (use system timezone) + + + Random + + + System timezone + + + Custom timezone + + + Specify a custom timezone (default UTC) + + + Random (for each page) + + + Choose Timezone... + + + Choose Timezone + + + Select + + diff --git a/components/content_settings/core/browser/content_settings_pref_provider.cc b/components/content_settings/core/browser/content_settings_pref_provider.cc --- a/components/content_settings/core/browser/content_settings_pref_provider.cc +++ b/components/content_settings/core/browser/content_settings_pref_provider.cc @@ -90,6 +90,8 @@ void PrefProvider::RegisterProfilePrefs( info->GetPrefRegistrationFlags()); } + registry->RegisterStringPref(prefs::kContentSettingsCustomTimezone, std::string()); + // Obsolete prefs ---------------------------------------------------------- // These prefs have been removed, but need to be registered so they can @@ -178,6 +180,10 @@ PrefProvider::PrefProvider(PrefService* prefs, event_args->set_number_of_exceptions( num_exceptions); // PrefProvider::PrefProvider. }); + + custom_timezone_ = + prefs_->GetString( + prefs::kContentSettingsCustomTimezone); } PrefProvider::~PrefProvider() { @@ -345,4 +351,14 @@ void PrefProvider::SetClockForTesting(base::Clock* clock) { clock_ = clock; } +void PrefProvider::GetPrefTimezoneOverrideValue(std::string& timezone) const { + timezone = custom_timezone_; +} + +void PrefProvider::SetPrefTimezoneOverrideValue(const std::string& timezone) { + prefs_->SetString( + prefs::kContentSettingsCustomTimezone, timezone); + custom_timezone_ = timezone; +} + } // namespace content_settings diff --git a/components/content_settings/core/browser/content_settings_pref_provider.h b/components/content_settings/core/browser/content_settings_pref_provider.h --- a/components/content_settings/core/browser/content_settings_pref_provider.h +++ b/components/content_settings/core/browser/content_settings_pref_provider.h @@ -65,6 +65,9 @@ class PrefProvider : public UserModifiableProvider { ContentSettingsPref* GetPref(ContentSettingsType type) const; + void GetPrefTimezoneOverrideValue(std::string& timezone) const; + void SetPrefTimezoneOverrideValue(const std::string& timezone); + private: friend class DeadlockCheckerObserver; // For testing. @@ -96,6 +99,7 @@ class PrefProvider : public UserModifiableProvider { base::ThreadChecker thread_checker_; raw_ptr clock_; + std::string custom_timezone_; }; } // namespace content_settings diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc --- a/components/content_settings/core/browser/content_settings_registry.cc +++ b/components/content_settings/core/browser/content_settings_registry.cc @@ -589,6 +589,18 @@ void ContentSettingsRegistry::Init() { ContentSettingsInfo::PERSISTENT, ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS); + Register(ContentSettingsType::TIMEZONE_OVERRIDE, "timezone-override", CONTENT_SETTING_ALLOW, + WebsiteSettingsInfo::SYNCABLE, + AllowlistedSchemes(kChromeUIScheme, kChromeDevToolsScheme), + ValidSettings(CONTENT_SETTING_ALLOW, // use system time + CONTENT_SETTING_ASK, // custom timezone, default UTC + CONTENT_SETTING_BLOCK), // random + WebsiteSettingsInfo::TOP_ORIGIN_ONLY_SCOPE, + WebsiteSettingsRegistry::PLATFORM_ANDROID, + ContentSettingsInfo::INHERIT_IN_INCOGNITO, + ContentSettingsInfo::PERSISTENT, + ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS); + Register(ContentSettingsType::FEDERATED_IDENTITY_API, "webid-api", CONTENT_SETTING_ALLOW, WebsiteSettingsInfo::UNSYNCABLE, /*allowlisted_schemes=*/{}, 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 @@ -151,6 +151,13 @@ void GetRendererContentSettingRules(const HostContentSettingsMap* map, &(rules->script_rules)); map->GetSettingsForOneType(ContentSettingsType::POPUPS, &(rules->popup_redirect_rules)); + + // pass custom timezone rules and value to the render process + map->GetSettingsForOneType(ContentSettingsType::TIMEZONE_OVERRIDE, + &(rules->timezone_override_rules)); + std::string timezone; + map->GetTimezoneOverrideValue(timezone); + rules->timezone_override_value = timezone; } bool IsMorePermissive(ContentSetting a, ContentSetting b) { diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc --- a/components/content_settings/core/browser/host_content_settings_map.cc +++ b/components/content_settings/core/browser/host_content_settings_map.cc @@ -602,6 +602,14 @@ void HostContentSettingsMap::SetClockForTesting(base::Clock* clock) { provider->SetClockForTesting(clock); } +void HostContentSettingsMap::GetTimezoneOverrideValue(std::string& custom_timezone) const { + GetPrefProvider()->GetPrefTimezoneOverrideValue(custom_timezone); +} + +void HostContentSettingsMap::SetTimezoneOverrideValue(const std::string& custom_timezone) { + GetPrefProvider()->SetPrefTimezoneOverrideValue(custom_timezone); +} + void HostContentSettingsMap::RecordExceptionMetrics() { auto* content_setting_registry = content_settings::ContentSettingsRegistry::GetInstance(); diff --git a/components/content_settings/core/browser/host_content_settings_map.h b/components/content_settings/core/browser/host_content_settings_map.h --- a/components/content_settings/core/browser/host_content_settings_map.h +++ b/components/content_settings/core/browser/host_content_settings_map.h @@ -329,6 +329,9 @@ class HostContentSettingsMap : public content_settings::Observer, allow_invalid_secondary_pattern_for_testing_ = allow; } + void GetTimezoneOverrideValue(std::string& custom_timezone) const; + void SetTimezoneOverrideValue(const std::string& custom_timezone); + private: friend class base::RefCountedThreadSafe; friend class content_settings::TestUtils; diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc --- a/components/content_settings/core/common/content_settings.cc +++ b/components/content_settings/core/common/content_settings.cc @@ -209,7 +209,8 @@ bool RendererContentSettingRules::IsRendererContentSetting( content_type == ContentSettingsType::JAVASCRIPT || content_type == ContentSettingsType::POPUPS || content_type == ContentSettingsType::MIXEDSCRIPT || - content_type == ContentSettingsType::AUTO_DARK_WEB_CONTENT; + content_type == ContentSettingsType::AUTO_DARK_WEB_CONTENT || + content_type == ContentSettingsType::TIMEZONE_OVERRIDE; } void RendererContentSettingRules::FilterRulesByOutermostMainFrameURL( @@ -219,6 +220,7 @@ void RendererContentSettingRules::FilterRulesByOutermostMainFrameURL( FilterRulesForType(popup_redirect_rules, outermost_main_frame_url); FilterRulesForType(mixed_content_rules, outermost_main_frame_url); FilterRulesForType(auto_dark_content_rules, outermost_main_frame_url); + FilterRulesForType(timezone_override_rules, outermost_main_frame_url); } RendererContentSettingRules::RendererContentSettingRules() = default; diff --git a/components/content_settings/core/common/content_settings.h b/components/content_settings/core/common/content_settings.h --- a/components/content_settings/core/common/content_settings.h +++ b/components/content_settings/core/common/content_settings.h @@ -93,6 +93,8 @@ struct RendererContentSettingRules { ContentSettingsForOneType popup_redirect_rules; ContentSettingsForOneType mixed_content_rules; ContentSettingsForOneType auto_dark_content_rules; + ContentSettingsForOneType timezone_override_rules; + std::string timezone_override_value; }; namespace content_settings { diff --git a/components/content_settings/core/common/content_settings.mojom b/components/content_settings/core/common/content_settings.mojom --- a/components/content_settings/core/common/content_settings.mojom +++ b/components/content_settings/core/common/content_settings.mojom @@ -78,4 +78,6 @@ struct RendererContentSettingRules { array popup_redirect_rules; array mixed_content_rules; array auto_dark_content_rules; + array timezone_override_rules; + string timezone_override_value; }; diff --git a/components/content_settings/core/common/content_settings_mojom_traits.cc b/components/content_settings/core/common/content_settings_mojom_traits.cc --- a/components/content_settings/core/common/content_settings_mojom_traits.cc +++ b/components/content_settings/core/common/content_settings_mojom_traits.cc @@ -102,7 +102,9 @@ bool StructTraitsscript_rules) && data.ReadPopupRedirectRules(&out->popup_redirect_rules) && data.ReadMixedContentRules(&out->mixed_content_rules) && - data.ReadAutoDarkContentRules(&out->auto_dark_content_rules); + data.ReadAutoDarkContentRules(&out->auto_dark_content_rules) && + data.ReadTimezoneOverrideRules(&out->timezone_override_rules) && + data.ReadTimezoneOverrideValue(&out->timezone_override_value); } } // namespace mojo diff --git a/components/content_settings/core/common/content_settings_mojom_traits.h b/components/content_settings/core/common/content_settings_mojom_traits.h --- a/components/content_settings/core/common/content_settings_mojom_traits.h +++ b/components/content_settings/core/common/content_settings_mojom_traits.h @@ -150,6 +150,16 @@ struct StructTraits< return r.auto_dark_content_rules; } + static const std::vector& timezone_override_rules( + const RendererContentSettingRules& r) { + return r.timezone_override_rules; + } + + static const std::string& timezone_override_value( + const RendererContentSettingRules& r) { + return r.timezone_override_value; + } + static bool Read( content_settings::mojom::RendererContentSettingRulesDataView data, RendererContentSettingRules* out); diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h --- a/components/content_settings/core/common/content_settings_types.h +++ b/components/content_settings/core/common/content_settings_types.h @@ -226,6 +226,9 @@ enum class ContentSettingsType : int32_t { // by the File System Access API. FILE_SYSTEM_LAST_PICKED_DIRECTORY, + // Content setting for timezone customization functionality. + TIMEZONE_OVERRIDE, + // Controls access to the getDisplayMedia API when {preferCurrentTab: true} // is specified. // TODO(crbug.com/1150788): Also apply this when getDisplayMedia() is called diff --git a/components/content_settings/core/common/pref_names.cc b/components/content_settings/core/common/pref_names.cc --- a/components/content_settings/core/common/pref_names.cc +++ b/components/content_settings/core/common/pref_names.cc @@ -172,4 +172,7 @@ const char kDesktopSitePeripheralSettingEnabled[] = const char kDesktopSiteDisplaySettingEnabled[] = "desktop_site.display_setting"; #endif +const char kContentSettingsCustomTimezone[] = + "profile.content_settings.custom_timezone"; + } // namespace prefs diff --git a/components/content_settings/core/common/pref_names.h b/components/content_settings/core/common/pref_names.h --- a/components/content_settings/core/common/pref_names.h +++ b/components/content_settings/core/common/pref_names.h @@ -89,6 +89,8 @@ extern const char kDesktopSitePeripheralSettingEnabled[]; extern const char kDesktopSiteDisplaySettingEnabled[]; #endif +extern const char kContentSettingsCustomTimezone[]; + } // namespace prefs #endif // COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_PREF_NAMES_H_ diff --git a/components/content_settings/renderer/content_settings_agent_impl.cc b/components/content_settings/renderer/content_settings_agent_impl.cc --- a/components/content_settings/renderer/content_settings_agent_impl.cc +++ b/components/content_settings/renderer/content_settings_agent_impl.cc @@ -8,8 +8,10 @@ #include "base/bind.h" #include "base/feature_list.h" +#include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" +#include "base/rand_util.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings.mojom.h" #include "components/content_settings/core/common/content_settings_pattern.h" @@ -321,6 +323,10 @@ bool ContentSettingsAgentImpl::AllowScript(bool enabled_per_settings) { allow = allow || IsAllowlistedForContentSettings(); cached_script_permissions_[frame] = allow; + + if (allow) + UpdateOverrides(); + return allow; } @@ -457,4 +463,81 @@ bool ContentSettingsAgentImpl::IsAllowlistedForContentSettings() const { return false; } +bool ContentSettingsAgentImpl::UpdateOverrides() { + // Evaluate the content setting rules + ContentSetting setting = CONTENT_SETTING_ALLOW; + + if (content_setting_rules_) { + blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); + + setting = GetContentSettingFromRules( + content_setting_rules_->timezone_override_rules, + url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL()); + } + return UpdateTimeZoneOverride( + setting, content_setting_rules_->timezone_override_value); + //&& UpdateLocaleOverride(setting); +} + +bool ContentSettingsAgentImpl::UpdateTimeZoneOverride( + ContentSetting setting, + const std::string& timezone_override_value) { + // base/i18n/icu_util.cc # 329 + + /* timezone_id: third_party/icu/source/i18n/timezone.cpp + We first try to lookup the zone ID in our system list. If this + * fails, we try to parse it as a custom string GMT[+-]hh:mm. If + * all else fails, we return GMT, which is probably not what the + * user wants, but at least is a functioning TimeZone object. + */ + String timezone_id; + + if (setting == CONTENT_SETTING_ALLOW) { + // system time + if (timezone_override_) { + timezone_override_.reset(); + } + return true; + } else if (setting == CONTENT_SETTING_BLOCK) { + // timezone random + UErrorCode ec = U_ZERO_ERROR; + int32_t rawOffset = base::RandInt(-12, 11) * 3600 * 1000; + icu::StringEnumeration* timezones = icu::TimeZone::createEnumeration( + rawOffset); // Obtain timezones by GMT timezone offset + if (timezones) { + const char* tzID; + int32_t length; + if ((tzID = timezones->next(&length, ec)) != NULL) { + timezone_id = String(tzID); + } + delete timezones; + } + } else if (setting == CONTENT_SETTING_ASK) { + if (timezone_override_value.empty()) + timezone_id = "Europe/London"; + else + timezone_id = String(timezone_override_value.c_str()); + } + + if (blink::TimeZoneController::HasTimeZoneOverride() == false) { + timezone_override_.reset(); + timezone_override_ = + blink::TimeZoneController::SetTimeZoneOverride(timezone_id); + if (!timezone_override_) { + LOG(WARNING) << "UpdateTimeZoneOverride - Invalid timezone id '" + << timezone_id << "'"; + return false; + } else { + LOG(INFO) + << "UpdateTimeZoneOverride - setting to '" + << timezone_id << "'"; + return true; + } + } else { + LOG(INFO) + << "UpdateTimeZoneOverride: already set"; + return false; + } +} + } // namespace content_settings diff --git a/components/content_settings/renderer/content_settings_agent_impl.h b/components/content_settings/renderer/content_settings_agent_impl.h --- a/components/content_settings/renderer/content_settings_agent_impl.h +++ b/components/content_settings/renderer/content_settings_agent_impl.h @@ -25,6 +25,11 @@ #include "url/gurl.h" #include "url/origin.h" +#include "third_party/blink/renderer/core/inspector/locale_controller.h" +#include "third_party/blink/renderer/core/timezone/timezone_controller.h" +#include "third_party/icu/source/common/unicode/strenum.h" +#include "third_party/icu/source/i18n/unicode/timezone.h" + namespace blink { class WebFrame; class WebURL; @@ -167,6 +172,12 @@ class ContentSettingsAgentImpl std::unique_ptr delegate_; mojo::AssociatedReceiverSet receivers_; + + std::unique_ptr timezone_override_; + + bool UpdateOverrides(); + bool UpdateTimeZoneOverride(ContentSetting setting, const std::string& timezone_override_value); + bool UpdateLocaleOverride(ContentSetting setting); }; } // namespace content_settings diff --git a/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java b/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java --- a/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java @@ -148,6 +148,9 @@ public class WebLayerSiteSettingsDelegate @Override public void dismissPrivacySandboxSnackbar() {} + @Override + public void launchTimeZoneOverrideHelpAndFeedbackActivity(Activity currentActivity) {} + @Override public boolean isFirstPartySetsDataAccessEnabled() { return false; -- 2.25.1