Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/web_restrictions/browser/web_restrictions_client.h" | 5 #include "components/web_restrictions/browser/web_restrictions_client.h" |
| 6 | 6 |
| 7 #include "base/android/jni_string.h" | 7 #include "base/android/jni_string.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/thread_task_runner_handle.h" | 10 #include "base/thread_task_runner_handle.h" |
| 11 #include "content/public/browser/browser_thread.h" | 11 #include "content/public/browser/browser_thread.h" |
| 12 #include "jni/WebRestrictionsClient_jni.h" | 12 #include "jni/WebRestrictionsClient_jni.h" |
| 13 | 13 |
| 14 using base::android::ScopedJavaGlobalRef; | 14 using base::android::ScopedJavaGlobalRef; |
| 15 | 15 |
| 16 namespace web_restrictions { | 16 namespace web_restrictions { |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 const size_t kMaxCacheSize = 100; | 20 const size_t kMaxCacheSize = 100; |
| 21 | 21 |
| 22 bool RequestPermissionTask( | 22 bool RequestPermissionTask( |
| 23 const GURL& url, | 23 const std::string& url, |
| 24 const base::android::JavaRef<jobject>& java_provider) { | 24 const base::android::JavaRef<jobject>& java_provider) { |
| 25 JNIEnv* env = base::android::AttachCurrentThread(); | 25 JNIEnv* env = base::android::AttachCurrentThread(); |
| 26 return Java_WebRestrictionsClient_requestPermission( | 26 return Java_WebRestrictionsClient_requestPermission( |
| 27 env, java_provider.obj(), | 27 env, java_provider.obj(), |
| 28 base::android::ConvertUTF8ToJavaString(env, url.spec()).obj()); | 28 base::android::ConvertUTF8ToJavaString(env, url).obj()); |
| 29 } | 29 } |
| 30 | 30 |
| 31 bool CheckSupportsRequestTask( | 31 bool CheckSupportsRequestTask( |
| 32 const base::android::JavaRef<jobject>& java_provider) { | 32 const base::android::JavaRef<jobject>& java_provider) { |
| 33 JNIEnv* env = base::android::AttachCurrentThread(); | 33 JNIEnv* env = base::android::AttachCurrentThread(); |
| 34 return Java_WebRestrictionsClient_supportsRequest(env, java_provider.obj()); | 34 return Java_WebRestrictionsClient_supportsRequest(env, java_provider.obj()); |
| 35 } | 35 } |
| 36 | 36 |
| 37 } // namespace | 37 } // namespace |
| 38 | 38 |
| 39 // static | 39 // static |
| 40 bool WebRestrictionsClient::Register(JNIEnv* env) { | 40 bool WebRestrictionsClient::Register(JNIEnv* env) { |
| 41 return RegisterNativesImpl(env); | 41 return RegisterNativesImpl(env); |
| 42 } | 42 } |
| 43 | 43 |
| 44 WebRestrictionsClient::WebRestrictionsClient() | 44 WebRestrictionsClient::WebRestrictionsClient() |
| 45 : initialized_(false), supports_request_(false) { | 45 : initialized_(false), supports_request_(false) { |
| 46 single_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 46 io_thread_task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread( |
|
Bernhard Bauer
2016/04/18 14:48:34
If you are not injecting this as a dependency, jus
aberent
2016/05/18 20:06:50
Done.
| |
| 47 content::BrowserThread::IO); | |
| 47 base::SequencedWorkerPool* worker_pool = | 48 base::SequencedWorkerPool* worker_pool = |
| 48 content::BrowserThread::GetBlockingPool(); | 49 content::BrowserThread::GetBlockingPool(); |
| 49 background_task_runner_ = | 50 background_task_runner_ = |
| 50 worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( | 51 worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( |
| 51 worker_pool->GetSequenceToken(), | 52 worker_pool->GetSequenceToken(), |
| 52 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 53 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| 53 } | 54 } |
| 54 | 55 |
| 55 WebRestrictionsClient::~WebRestrictionsClient() { | 56 WebRestrictionsClient::~WebRestrictionsClient() { |
| 56 if (java_provider_.is_null()) | 57 if (java_provider_.is_null()) |
| 57 return; | 58 return; |
| 58 JNIEnv* env = base::android::AttachCurrentThread(); | 59 JNIEnv* env = base::android::AttachCurrentThread(); |
| 59 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); | 60 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); |
| 60 java_provider_.Reset(); | 61 java_provider_.Reset(); |
| 61 } | 62 } |
| 62 | 63 |
| 63 void WebRestrictionsClient::SetAuthority( | 64 void WebRestrictionsClient::SetAuthority( |
| 64 const std::string& content_provider_authority) { | 65 const std::string& content_provider_authority) { |
| 65 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 66 // This is called from the UI thread in normal use. |
| 67 if (io_thread_task_runner_->BelongsToCurrentThread()) { | |
| 68 // Only used for testing. Avoids need for complex multithreading in tests. | |
| 69 SetAuthorityTask(content_provider_authority); | |
|
Bernhard Bauer
2016/04/18 14:48:34
You could just friend the test class and call SetA
aberent
2016/05/18 20:06:50
Done.
| |
| 70 } else { | |
| 71 // Run a task on the IO thread to do the real work. | |
| 72 io_thread_task_runner_->PostTask( | |
| 73 FROM_HERE, | |
| 74 base::Bind(&WebRestrictionsClient::SetAuthorityTask, | |
| 75 base::Unretained(this), content_provider_authority)); | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 void WebRestrictionsClient::SetAuthorityTask( | |
| 80 const std::string& content_provider_authority) { | |
| 81 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); | |
| 66 // Destroy any existing content resolver. | 82 // Destroy any existing content resolver. |
| 67 JNIEnv* env = base::android::AttachCurrentThread(); | 83 JNIEnv* env = base::android::AttachCurrentThread(); |
| 68 if (!java_provider_.is_null()) { | 84 if (!java_provider_.is_null()) { |
| 69 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); | 85 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); |
| 70 java_provider_.Reset(); | 86 java_provider_.Reset(); |
| 71 } | 87 } |
| 72 ClearCache(); | 88 ClearCache(); |
| 73 provider_authority_ = content_provider_authority; | 89 provider_authority_ = content_provider_authority; |
| 74 | 90 |
| 75 // Initialize the content resolver. | 91 // Initialize the content resolver. |
| 76 initialized_ = !content_provider_authority.empty(); | 92 initialized_ = !content_provider_authority.empty(); |
| 77 if (!initialized_) | 93 if (!initialized_) |
| 78 return; | 94 return; |
| 79 java_provider_.Reset(Java_WebRestrictionsClient_create( | 95 java_provider_.Reset(Java_WebRestrictionsClient_create( |
| 80 env, | 96 env, |
| 81 base::android::ConvertUTF8ToJavaString(env, content_provider_authority) | 97 base::android::ConvertUTF8ToJavaString(env, content_provider_authority) |
| 82 .obj(), | 98 .obj(), |
| 83 reinterpret_cast<jlong>(this))); | 99 reinterpret_cast<jlong>(this))); |
| 84 supports_request_ = false; | 100 supports_request_ = false; |
| 85 base::PostTaskAndReplyWithResult( | 101 base::PostTaskAndReplyWithResult( |
| 86 content::BrowserThread::GetBlockingPool(), FROM_HERE, | 102 content::BrowserThread::GetBlockingPool(), FROM_HERE, |
| 87 base::Bind(&CheckSupportsRequestTask, java_provider_), | 103 base::Bind(&CheckSupportsRequestTask, java_provider_), |
| 88 base::Bind(&WebRestrictionsClient::RequestSupportKnown, | 104 base::Bind(&WebRestrictionsClient::RequestSupportKnown, |
| 89 base::Unretained(this), provider_authority_)); | 105 base::Unretained(this), provider_authority_)); |
| 90 } | 106 } |
| 91 | 107 |
| 92 UrlAccess WebRestrictionsClient::ShouldProceed( | 108 UrlAccess WebRestrictionsClient::ShouldProceed( |
| 93 bool is_main_frame, | 109 bool is_main_frame, |
| 94 const GURL& url, | 110 const std::string& url, |
| 95 const base::Callback<void(bool)>& callback) { | 111 const base::Callback<void(bool)>& callback) { |
| 96 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 112 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); |
| 97 if (!initialized_) | 113 if (!initialized_) |
| 98 return ALLOW; | 114 return ALLOW; |
| 99 auto iter = cache_.find(url); | 115 |
| 100 if (iter != cache_.end()) { | 116 std::unique_ptr<const WebRestrictionsClientResult> result = |
| 117 cache_.GetCacheEntry(url); | |
| 118 if (result.get()) { | |
|
Bernhard Bauer
2016/04/18 14:48:34
The .get() is unnecessary -- unique_ptr has a bool
aberent
2016/05/18 20:06:50
Done.
| |
| 101 RecordURLAccess(url); | 119 RecordURLAccess(url); |
| 102 JNIEnv* env = base::android::AttachCurrentThread(); | 120 return result->ShouldProceed() ? ALLOW : DISALLOW; |
| 103 return Java_ShouldProceedResult_shouldProceed(env, iter->second.obj()) | |
| 104 ? ALLOW | |
| 105 : DISALLOW; | |
| 106 } | 121 } |
| 107 base::PostTaskAndReplyWithResult( | 122 base::PostTaskAndReplyWithResult( |
| 108 background_task_runner_.get(), FROM_HERE, | 123 background_task_runner_.get(), FROM_HERE, |
| 109 base::Bind(&WebRestrictionsClient::ShouldProceedTask, url, | 124 base::Bind(&WebRestrictionsClient::ShouldProceedTask, url, |
| 110 java_provider_), | 125 java_provider_), |
| 111 base::Bind(&WebRestrictionsClient::OnShouldProceedComplete, | 126 base::Bind(&WebRestrictionsClient::OnShouldProceedComplete, |
| 112 base::Unretained(this), provider_authority_, url, callback)); | 127 base::Unretained(this), provider_authority_, url, callback)); |
| 113 | 128 |
| 114 return PENDING; | 129 return PENDING; |
| 115 } | 130 } |
| 116 | 131 |
| 117 bool WebRestrictionsClient::SupportsRequest() const { | 132 bool WebRestrictionsClient::SupportsRequest() const { |
| 118 return initialized_ && supports_request_; | 133 return initialized_ && supports_request_; |
| 119 } | 134 } |
| 120 | 135 |
| 121 int WebRestrictionsClient::GetResultColumnCount(const GURL& url) const { | |
| 122 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 123 if (!initialized_) | |
| 124 return 0; | |
| 125 auto iter = cache_.find(url); | |
| 126 if (iter == cache_.end()) | |
| 127 return 0; | |
| 128 return Java_ShouldProceedResult_getColumnCount( | |
| 129 base::android::AttachCurrentThread(), iter->second.obj()); | |
| 130 } | |
| 131 | |
| 132 std::string WebRestrictionsClient::GetResultColumnName(const GURL& url, | |
| 133 int column) const { | |
| 134 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 135 if (!initialized_) | |
| 136 return std::string(); | |
| 137 auto iter = cache_.find(url); | |
| 138 if (iter == cache_.end()) | |
| 139 return std::string(); | |
| 140 | |
| 141 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 142 return base::android::ConvertJavaStringToUTF8( | |
| 143 env, | |
| 144 Java_ShouldProceedResult_getColumnName(env, iter->second.obj(), column) | |
| 145 .obj()); | |
| 146 } | |
| 147 | |
| 148 int WebRestrictionsClient::GetResultIntValue(const GURL& url, | |
| 149 int column) const { | |
| 150 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 151 if (!initialized_) | |
| 152 return 0; | |
| 153 auto iter = cache_.find(url); | |
| 154 if (iter == cache_.end()) | |
| 155 return 0; | |
| 156 return Java_ShouldProceedResult_getInt(base::android::AttachCurrentThread(), | |
| 157 iter->second.obj(), column); | |
| 158 } | |
| 159 | |
| 160 std::string WebRestrictionsClient::GetResultStringValue(const GURL& url, | |
| 161 int column) const { | |
| 162 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 163 if (!initialized_) | |
| 164 return std::string(); | |
| 165 auto iter = cache_.find(url); | |
| 166 if (iter == cache_.end()) | |
| 167 return std::string(); | |
| 168 | |
| 169 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 170 return base::android::ConvertJavaStringToUTF8( | |
| 171 env, Java_ShouldProceedResult_getString(env, iter->second.obj(), column) | |
| 172 .obj()); | |
| 173 } | |
| 174 | |
| 175 void WebRestrictionsClient::RequestPermission( | 136 void WebRestrictionsClient::RequestPermission( |
| 176 const GURL& url, | 137 const std::string& url, |
| 177 const base::Callback<void(bool)>& request_success) { | 138 const base::Callback<void(bool)>& request_success) { |
| 178 if (!initialized_) { | 139 if (!initialized_) { |
| 179 request_success.Run(false); | 140 request_success.Run(false); |
| 180 return; | 141 return; |
| 181 } | 142 } |
| 182 base::PostTaskAndReplyWithResult( | 143 base::PostTaskAndReplyWithResult( |
| 183 background_task_runner_.get(), FROM_HERE, | 144 background_task_runner_.get(), FROM_HERE, |
| 184 base::Bind(&RequestPermissionTask, url, java_provider_), request_success); | 145 base::Bind(&RequestPermissionTask, url, java_provider_), request_success); |
| 185 } | 146 } |
| 186 | 147 |
| 187 void WebRestrictionsClient::OnWebRestrictionsChanged() { | 148 void WebRestrictionsClient::OnWebRestrictionsChanged() { |
| 188 single_thread_task_runner_->PostTask( | 149 io_thread_task_runner_->PostTask( |
| 189 FROM_HERE, | 150 FROM_HERE, |
| 190 base::Bind(&WebRestrictionsClient::ClearCache, base::Unretained(this))); | 151 base::Bind(&WebRestrictionsClient::ClearCache, base::Unretained(this))); |
| 191 } | 152 } |
| 192 | 153 |
| 193 void WebRestrictionsClient::RecordURLAccess(const GURL& url) { | 154 void WebRestrictionsClient::RecordURLAccess(const std::string& url) { |
| 194 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 155 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); |
| 195 // Move the URL to the front of the cache. | 156 // Move the URL to the front of the cache. |
| 196 recent_urls_.remove(url); | 157 recent_urls_.remove(url); |
| 197 recent_urls_.push_front(url); | 158 recent_urls_.push_front(url); |
| 198 } | 159 } |
| 199 | 160 |
| 200 void WebRestrictionsClient::UpdateCache(std::string provider_authority, | 161 void WebRestrictionsClient::UpdateCache(std::string provider_authority, |
| 201 GURL url, | 162 std::string url, |
|
Bernhard Bauer
2016/04/18 14:48:34
This should be const-ref (as should have been the
aberent
2016/05/18 20:06:50
Done.
| |
| 202 ScopedJavaGlobalRef<jobject> result) { | 163 ScopedJavaGlobalRef<jobject> result) { |
| 203 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 164 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); |
| 204 // If the webrestrictions provider changed when the old one was being queried, | 165 // If the webrestrictions provider changed when the old one was being queried, |
| 205 // do not update the cache for the new provider. | 166 // do not update the cache for the new provider. |
| 206 if (provider_authority != provider_authority_) | 167 if (provider_authority != provider_authority_) |
| 207 return; | 168 return; |
| 208 RecordURLAccess(url); | 169 RecordURLAccess(url); |
| 209 if (recent_urls_.size() >= kMaxCacheSize) { | 170 if (recent_urls_.size() >= kMaxCacheSize) { |
| 210 cache_.erase(recent_urls_.back()); | 171 cache_.RemoveCacheEntry(recent_urls_.back()); |
| 211 recent_urls_.pop_back(); | 172 recent_urls_.pop_back(); |
| 212 } | 173 } |
| 213 cache_[url] = result; | 174 cache_.SetCacheEntry(url, WebRestrictionsClientResult(result)); |
| 214 } | 175 } |
| 215 | 176 |
| 216 void WebRestrictionsClient::RequestSupportKnown(std::string provider_authority, | 177 void WebRestrictionsClient::RequestSupportKnown(std::string provider_authority, |
| 217 bool supports_request) { | 178 bool supports_request) { |
| 218 // |supports_request_| is initialized to false. | 179 // |supports_request_| is initialized to false. |
| 219 DCHECK(!supports_request_); | 180 DCHECK(!supports_request_); |
| 220 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 181 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); |
| 221 // If the webrestrictions provider changed when the old one was being queried, | 182 // If the webrestrictions provider changed when the old one was being queried, |
| 222 // ignore the result. | 183 // ignore the result. |
| 223 if (provider_authority != provider_authority_) | 184 if (provider_authority != provider_authority_) |
| 224 return; | 185 return; |
| 225 supports_request_ = supports_request; | 186 supports_request_ = supports_request; |
| 226 } | 187 } |
| 227 | 188 |
| 228 void WebRestrictionsClient::OnShouldProceedComplete( | 189 void WebRestrictionsClient::OnShouldProceedComplete( |
| 229 std::string provider_authority, | 190 std::string provider_authority, |
| 230 const GURL& url, | 191 const std::string& url, |
| 231 const base::Callback<void(bool)>& callback, | 192 const base::Callback<void(bool)>& callback, |
| 232 const ScopedJavaGlobalRef<jobject>& result) { | 193 const ScopedJavaGlobalRef<jobject>& result) { |
| 233 UpdateCache(provider_authority, url, result); | 194 UpdateCache(provider_authority, url, result); |
| 234 JNIEnv* env = base::android::AttachCurrentThread(); | 195 callback.Run(cache_.GetCacheEntry(url)->ShouldProceed()); |
| 235 callback.Run(Java_ShouldProceedResult_shouldProceed(env, result.obj())); | |
| 236 } | 196 } |
| 237 | 197 |
| 238 void WebRestrictionsClient::ClearCache() { | 198 void WebRestrictionsClient::ClearCache() { |
| 239 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 199 DCHECK(io_thread_task_runner_->BelongsToCurrentThread()); |
| 240 cache_.clear(); | 200 cache_.Clear(); |
| 241 recent_urls_.clear(); | 201 recent_urls_.clear(); |
| 242 } | 202 } |
| 243 | 203 |
| 204 std::unique_ptr<const WebRestrictionsClientResult> | |
| 205 WebRestrictionsClient::GetCachedWebRestrictionsResult(const std::string& url) { | |
| 206 return cache_.GetCacheEntry(url); | |
| 207 } | |
| 208 | |
| 244 // static | 209 // static |
| 245 ScopedJavaGlobalRef<jobject> WebRestrictionsClient::ShouldProceedTask( | 210 ScopedJavaGlobalRef<jobject> WebRestrictionsClient::ShouldProceedTask( |
| 246 const GURL& url, | 211 const std::string& url, |
| 247 const base::android::JavaRef<jobject>& java_provider) { | 212 const base::android::JavaRef<jobject>& java_provider) { |
| 248 JNIEnv* env = base::android::AttachCurrentThread(); | 213 JNIEnv* env = base::android::AttachCurrentThread(); |
| 249 base::android::ScopedJavaGlobalRef<jobject> result( | 214 base::android::ScopedJavaGlobalRef<jobject> result( |
| 250 Java_WebRestrictionsClient_shouldProceed( | 215 Java_WebRestrictionsClient_shouldProceed( |
| 251 env, java_provider.obj(), | 216 env, java_provider.obj(), |
| 252 base::android::ConvertUTF8ToJavaString(env, url.spec()).obj())); | 217 base::android::ConvertUTF8ToJavaString(env, url).obj())); |
| 253 return result; | 218 return result; |
| 254 } | 219 } |
| 255 | 220 |
| 221 std::unique_ptr<const WebRestrictionsClientResult> | |
| 222 WebRestrictionsCache::GetCacheEntry(const std::string& url) { | |
| 223 lock_.Acquire(); | |
|
Bernhard Bauer
2016/04/18 14:48:34
Use base::AutoLock for this. That way you can also
aberent
2016/05/18 20:06:50
Done.
| |
| 224 std::unique_ptr<const WebRestrictionsClientResult> result; | |
| 225 auto iter = cache_data_.find(url); | |
| 226 if (iter != cache_data_.end()) | |
| 227 // This has to be thread-safe, so copy the data. | |
| 228 result.reset(new WebRestrictionsClientResult(iter->second)); | |
| 229 lock_.Release(); | |
| 230 return result; | |
| 231 } | |
| 232 | |
| 233 void WebRestrictionsCache::SetCacheEntry( | |
| 234 const std::string& url, | |
| 235 const WebRestrictionsClientResult& entry) { | |
| 236 lock_.Acquire(); | |
| 237 cache_data_[url] = entry; | |
| 238 lock_.Release(); | |
| 239 } | |
| 240 | |
| 241 void WebRestrictionsCache::RemoveCacheEntry(const std::string& url) { | |
| 242 lock_.Acquire(); | |
| 243 cache_data_.erase(url); | |
| 244 lock_.Release(); | |
| 245 } | |
| 246 | |
| 247 void WebRestrictionsCache::Clear() { | |
| 248 lock_.Acquire(); | |
| 249 cache_data_.clear(); | |
| 250 lock_.Release(); | |
| 251 } | |
| 252 | |
| 256 void NotifyWebRestrictionsChanged( | 253 void NotifyWebRestrictionsChanged( |
|
Bernhard Bauer
2016/04/18 14:48:34
Actually, we could remove this and just directly c
aberent
2016/05/18 20:06:50
Done.
| |
| 257 JNIEnv* env, | 254 JNIEnv* env, |
| 258 const base::android::JavaParamRef<jobject>& clazz, | 255 const base::android::JavaParamRef<jobject>& clazz, |
| 259 jlong provider_ptr) { | 256 jlong provider_ptr) { |
| 260 WebRestrictionsClient* provider = | 257 WebRestrictionsClient* provider = |
| 261 reinterpret_cast<WebRestrictionsClient*>(provider_ptr); | 258 reinterpret_cast<WebRestrictionsClient*>(provider_ptr); |
| 262 // TODO(knn): Also reload existing interstitials/error pages. | 259 // TODO(knn): Also reload existing interstitials/error pages. |
| 263 provider->OnWebRestrictionsChanged(); | 260 provider->OnWebRestrictionsChanged(); |
| 264 } | 261 } |
| 265 | 262 |
| 266 } // namespace web_restrictions | 263 } // namespace web_restrictions |
| OLD | NEW |