Index: ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm |
diff --git a/ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm b/ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0e17a5fbd72ded62a21bbe9cabbe03c2d54cefb9 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.mm |
@@ -0,0 +1,125 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h" |
+ |
+#include "base/ios/weak_nsobject.h" |
+#include "base/scoped_observer.h" |
+#include "components/content_settings/core/browser/content_settings_details.h" |
+#include "components/content_settings/core/browser/content_settings_observer.h" |
+#include "components/content_settings/core/browser/host_content_settings_map.h" |
+#include "components/content_settings/core/common/content_settings.h" |
+#include "components/content_settings/core/common/content_settings_types.h" |
+ |
+@interface ContentSettingBackedBoolean () |
+ |
+// The ID of the setting in |settingsMap|. |
+@property(nonatomic, readonly) ContentSettingsType settingID; |
+ |
+// Whether the boolean value reflects the state of the preference that backs it, |
+// or its negation. |
+@property(nonatomic, assign, getter=isInverted) BOOL inverted; |
+ |
+// Whether this object is the one modifying the content setting. Used to filter |
+// out changes notifications. |
+@property(nonatomic, assign) BOOL isModifyingContentSetting; |
+ |
+@end |
+ |
+namespace { |
+ |
+typedef ScopedObserver<HostContentSettingsMap, content_settings::Observer> |
+ ContentSettingsObserver; |
+ |
+class ContentSettingsObserverBridge : public content_settings::Observer { |
+ public: |
+ explicit ContentSettingsObserverBridge(ContentSettingBackedBoolean* setting); |
+ ~ContentSettingsObserverBridge() override; |
+ |
+ // content_settings::Observer implementation. |
+ void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern, |
+ const ContentSettingsPattern& secondary_pattern, |
+ ContentSettingsType content_type, |
+ std::string resource_identifier) override; |
+ |
+ private: |
+ ContentSettingBackedBoolean* setting_; // weak |
+}; |
+ |
+ContentSettingsObserverBridge::ContentSettingsObserverBridge( |
+ ContentSettingBackedBoolean* setting) |
+ : setting_(setting) {} |
+ |
+ContentSettingsObserverBridge::~ContentSettingsObserverBridge() {} |
+ |
+void ContentSettingsObserverBridge::OnContentSettingChanged( |
+ const ContentSettingsPattern& primary_pattern, |
+ const ContentSettingsPattern& secondary_pattern, |
+ ContentSettingsType content_type, |
+ std::string resource_identifier) { |
+ // Ignore when it's the ContentSettingBackedBoolean that is changing the |
+ // content setting. |
+ if (setting_.isModifyingContentSetting) { |
+ return; |
+ } |
+ const ContentSettingsDetails settings_details( |
+ primary_pattern, secondary_pattern, content_type, resource_identifier); |
+ ContentSettingsType settingID = settings_details.type(); |
+ // Unfortunately, because the ContentSettingsPolicyProvider doesn't publish |
+ // the specific content setting on policy updates, we must refresh on every |
+ // CONTENT_SETTINGS_TYPE_DEFAULT notification. |
+ if (settingID != CONTENT_SETTINGS_TYPE_DEFAULT && |
+ settingID != setting_.settingID) { |
+ return; |
+ } |
+ // Notify the BooleanObserver. |
+ [setting_.observer booleanDidChange:setting_]; |
+} |
+ |
+} // namespace |
+ |
+@implementation ContentSettingBackedBoolean { |
+ ContentSettingsType settingID_; |
+ scoped_refptr<HostContentSettingsMap> settingsMap_; |
+ std::unique_ptr<ContentSettingsObserverBridge> adaptor_; |
+ std::unique_ptr<ContentSettingsObserver> content_settings_observer_; |
+} |
+ |
+@synthesize settingID = settingID_; |
+@synthesize observer = observer_; |
+@synthesize inverted = inverted_; |
+@synthesize isModifyingContentSetting = isModifyingContentSetting_; |
+ |
+- (id)initWithHostContentSettingsMap:(HostContentSettingsMap*)settingsMap |
+ settingID:(ContentSettingsType)settingID |
+ inverted:(BOOL)inverted { |
+ self = [super init]; |
+ if (self) { |
+ settingID_ = settingID; |
+ settingsMap_ = settingsMap; |
+ inverted_ = inverted; |
+ // Listen for changes to the content setting. |
+ adaptor_.reset(new ContentSettingsObserverBridge(self)); |
+ content_settings_observer_.reset( |
+ new ContentSettingsObserver(adaptor_.get())); |
+ content_settings_observer_->Add(settingsMap); |
+ } |
+ return self; |
+} |
+ |
+- (BOOL)value { |
+ ContentSetting setting = |
+ settingsMap_->GetDefaultContentSetting(settingID_, NULL); |
+ return self.inverted ^ (setting == CONTENT_SETTING_ALLOW); |
+} |
+ |
+- (void)setValue:(BOOL)value { |
+ ContentSetting setting = |
+ (self.inverted ^ value) ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; |
+ self.isModifyingContentSetting = YES; |
+ settingsMap_->SetDefaultContentSetting(settingID_, setting); |
+ self.isModifyingContentSetting = NO; |
+} |
+ |
+@end |