summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorboliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-22 18:53:04 +0000
committerboliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-22 18:53:04 +0000
commit2a3a0596a6a5d0703ff49df9d45fd57e9db96959 (patch)
tree77b52f512dd593a3c9a9a335c02c8c5065aadb37
parent6f356a88e6587d7d206f6327b0771e810609cf70 (diff)
downloadchromium_src-2a3a0596a6a5d0703ff49df9d45fd57e9db96959.zip
chromium_src-2a3a0596a6a5d0703ff49df9d45fd57e9db96959.tar.gz
chromium_src-2a3a0596a6a5d0703ff49df9d45fd57e9db96959.tar.bz2
Implement WebStorage API methods
Most of the methods involves calling methods to QuotaManager on the IO thread and translating the arguments between Java and native code. Introduce AwQuotaManagerBridge to facilitate this logic. The Java AwQuotaManagerBridge is currently a singleton but should be owned by AwBrowserContext when we have one. The native one is owned by native AwBrowserContext. Java calls the corresponding native AwBrowserContext to obtain the pointer. Introduced JniDependencyFactory interface used to create native objects under native but is used or passed in BrowserContext or ContentsBrowserClient. Also added base::android::ToJavaLongArray to convert to Java long arrays. BUG= Android only change. Ran through android bots. NOTRY=true Review URL: https://chromiumcodereview.appspot.com/12253057 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184139 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--android_webview/android_webview.gyp3
-rw-r--r--android_webview/browser/aw_browser_context.cc17
-rw-r--r--android_webview/browser/aw_browser_context.h14
-rw-r--r--android_webview/browser/aw_content_browser_client.cc17
-rw-r--r--android_webview/browser/aw_content_browser_client.h14
-rw-r--r--android_webview/browser/aw_quota_manager_bridge.cc9
-rw-r--r--android_webview/browser/aw_quota_manager_bridge.h18
-rw-r--r--android_webview/browser/aw_quota_permission_context.cc12
-rw-r--r--android_webview/browser/jni_dependency_factory.h34
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java162
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java291
-rw-r--r--android_webview/lib/aw_browser_dependency_factory_impl.cc1
-rw-r--r--android_webview/lib/main/aw_main_delegate.cc23
-rw-r--r--android_webview/lib/main/aw_main_delegate.h12
-rw-r--r--android_webview/native/android_webview_jni_registrar.cc2
-rw-r--r--android_webview/native/aw_geolocation_permission_context.cc2
-rw-r--r--android_webview/native/aw_geolocation_permission_context.h5
-rw-r--r--android_webview/native/aw_quota_manager_bridge_impl.cc337
-rw-r--r--android_webview/native/aw_quota_manager_bridge_impl.h74
-rw-r--r--android_webview/native/webview_native.gyp3
-rw-r--r--base/android/jni_array.cc20
-rw-r--r--base/android/jni_array.h7
-rw-r--r--base/android/jni_array_unittest.cc28
23 files changed, 1068 insertions, 37 deletions
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index 4f199f1..47117fc 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -107,6 +107,8 @@
'browser/aw_http_auth_handler_base.h',
'browser/aw_login_delegate.cc',
'browser/aw_login_delegate.h',
+ 'browser/aw_quota_manager_bridge.cc',
+ 'browser/aw_quota_manager_bridge.h',
'browser/aw_quota_permission_context.cc',
'browser/aw_quota_permission_context.h',
'browser/aw_request_interceptor.cc',
@@ -121,6 +123,7 @@
'browser/icon_helper.h',
'browser/input_stream.h',
'browser/intercepted_request_data.h',
+ 'browser/jni_dependency_factory.h',
'browser/net/android_stream_reader_url_request_job.cc',
'browser/net/android_stream_reader_url_request_job.h',
'browser/net/aw_network_delegate.cc',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index ccef830..85a1c14 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -4,6 +4,8 @@
#include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_quota_manager_bridge.h"
+#include "android_webview/browser/jni_dependency_factory.h"
#include "android_webview/browser/net/aw_url_request_context_getter.h"
#include "components/visitedlink/browser/visitedlink_master.h"
#include "content/public/browser/browser_thread.h"
@@ -42,9 +44,9 @@ class AwResourceContext : public content::ResourceContext {
AwBrowserContext::AwBrowserContext(
const base::FilePath path,
- GeolocationPermissionFactoryFn* geolocation_permission_factory)
+ JniDependencyFactory* native_factory)
: context_storage_path_(path),
- geolocation_permission_factory_(geolocation_permission_factory) {
+ native_factory_(native_factory) {
}
AwBrowserContext::~AwBrowserContext() {
@@ -110,6 +112,14 @@ AwBrowserContext::CreateRequestContextForStoragePartition(
return url_request_context_getter_.get();
}
+AwQuotaManagerBridge* AwBrowserContext::GetQuotaManagerBridge() {
+ if (!quota_manager_bridge_) {
+ quota_manager_bridge_.reset(
+ native_factory_->CreateAwQuotaManagerBridge(this));
+ }
+ return quota_manager_bridge_.get();
+}
+
base::FilePath AwBrowserContext::GetPath() {
return context_storage_path_;
}
@@ -163,7 +173,8 @@ AwBrowserContext::GetDownloadManagerDelegate() {
content::GeolocationPermissionContext*
AwBrowserContext::GetGeolocationPermissionContext() {
if (!geolocation_permission_context_) {
- geolocation_permission_context_ = (*geolocation_permission_factory_)();
+ geolocation_permission_context_ =
+ native_factory_->CreateGeolocationPermission(this);
}
return geolocation_permission_context_;
}
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index 4d0bd66..517f307 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -32,16 +32,15 @@ class WebContents;
namespace android_webview {
class AwURLRequestContextGetter;
-
-typedef content::GeolocationPermissionContext* GeolocationPermissionFactoryFn();
+class AwQuotaManagerBridge;
+class JniDependencyFactory;
class AwBrowserContext : public content::BrowserContext,
public components::VisitedLinkDelegate {
public:
- AwBrowserContext(
- const base::FilePath path,
- GeolocationPermissionFactoryFn* geolocation_permission_factory);
+ AwBrowserContext(const base::FilePath path,
+ JniDependencyFactory* native_factory);
virtual ~AwBrowserContext();
// Convenience method to returns the AwBrowserContext corresponding to the
@@ -83,6 +82,8 @@ class AwBrowserContext : public content::BrowserContext,
scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>
chrome_devtools_protocol_handler);
+ AwQuotaManagerBridge* GetQuotaManagerBridge();
+
// content::BrowserContext implementation.
virtual base::FilePath GetPath() OVERRIDE;
virtual bool IsOffTheRecord() const OVERRIDE;
@@ -112,10 +113,11 @@ class AwBrowserContext : public content::BrowserContext,
// The file path where data for this context is persisted.
base::FilePath context_storage_path_;
+ JniDependencyFactory* native_factory_;
scoped_refptr<AwURLRequestContextGetter> url_request_context_getter_;
- GeolocationPermissionFactoryFn* geolocation_permission_factory_;
scoped_refptr<content::GeolocationPermissionContext>
geolocation_permission_context_;
+ scoped_ptr<AwQuotaManagerBridge> quota_manager_bridge_;
AwDownloadManagerDelegate download_manager_delegate_;
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index bc4918b..0462e49 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -4,9 +4,11 @@
#include "android_webview/browser/aw_content_browser_client.h"
+#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_browser_main_parts.h"
#include "android_webview/browser/aw_cookie_access_policy.h"
#include "android_webview/browser/aw_quota_permission_context.h"
+#include "android_webview/browser/jni_dependency_factory.h"
#include "android_webview/browser/net_disk_cache_remover.h"
#include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h"
#include "android_webview/common/url_constants.h"
@@ -49,16 +51,21 @@ class AwAccessTokenStore : public content::AccessTokenStore {
namespace android_webview {
+// static
+AwContentBrowserClient* AwContentBrowserClient::FromContentBrowserClient(
+ content::ContentBrowserClient* client) {
+ return static_cast<AwContentBrowserClient*>(client);
+}
+
AwContentBrowserClient::AwContentBrowserClient(
- ViewDelegateFactoryFn* view_delegate_factory,
- GeolocationPermissionFactoryFn* geolocation_permission_factory)
- : view_delegate_factory_(view_delegate_factory) {
+ JniDependencyFactory* native_factory)
+ : native_factory_(native_factory) {
base::FilePath user_data_dir;
if (!PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir)) {
NOTREACHED() << "Failed to get app data directory for Android WebView";
}
browser_context_.reset(
- new AwBrowserContext(user_data_dir, geolocation_permission_factory));
+ new AwBrowserContext(user_data_dir, native_factory_));
}
AwContentBrowserClient::~AwContentBrowserClient() {
@@ -86,7 +93,7 @@ content::BrowserMainParts* AwContentBrowserClient::CreateBrowserMainParts(
content::WebContentsViewDelegate*
AwContentBrowserClient::GetWebContentsViewDelegate(
content::WebContents* web_contents) {
- return (*view_delegate_factory_)(web_contents);
+ return native_factory_->CreateViewDelegate(web_contents);
}
void AwContentBrowserClient::RenderProcessHostCreated(
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 9ff4f6c..cae3aeb 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -5,7 +5,6 @@
#ifndef ANDROID_WEBVIEW_LIB_AW_CONTENT_BROWSER_CLIENT_H_
#define ANDROID_WEBVIEW_LIB_AW_CONTENT_BROWSER_CLIENT_H_
-#include "android_webview/browser/aw_browser_context.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
@@ -14,14 +13,15 @@
namespace android_webview {
+class AwBrowserContext;
+class JniDependencyFactory;
+
class AwContentBrowserClient : public content::ContentBrowserClient {
public:
- typedef content::WebContentsViewDelegate* ViewDelegateFactoryFn(
- content::WebContents* web_contents);
+ static AwContentBrowserClient* FromContentBrowserClient(
+ content::ContentBrowserClient* client);
- AwContentBrowserClient(
- ViewDelegateFactoryFn* view_delegate_factory,
- GeolocationPermissionFactoryFn* geolocation_permission_factory);
+ AwContentBrowserClient(JniDependencyFactory* native_factory);
virtual ~AwContentBrowserClient();
AwBrowserContext* GetAwBrowserContext();
@@ -164,7 +164,7 @@ class AwContentBrowserClient : public content::ContentBrowserClient {
// context.
scoped_ptr<AwBrowserContext> browser_context_;
- ViewDelegateFactoryFn* view_delegate_factory_;
+ JniDependencyFactory* native_factory_;
DISALLOW_COPY_AND_ASSIGN(AwContentBrowserClient);
};
diff --git a/android_webview/browser/aw_quota_manager_bridge.cc b/android_webview/browser/aw_quota_manager_bridge.cc
new file mode 100644
index 0000000..4a87cd6
--- /dev/null
+++ b/android_webview/browser/aw_quota_manager_bridge.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2013 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.
+
+#include "android_webview/browser/aw_quota_manager_bridge.h"
+
+namespace android_webview {
+AwQuotaManagerBridge::~AwQuotaManagerBridge() {}
+} // namespace android_webview
diff --git a/android_webview/browser/aw_quota_manager_bridge.h b/android_webview/browser/aw_quota_manager_bridge.h
new file mode 100644
index 0000000..5480cf8
--- /dev/null
+++ b/android_webview/browser/aw_quota_manager_bridge.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2013 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.
+
+#ifndef ANDROID_WEBVIEW_BROWSER_AW_QUOTA_MANAGER_BRIDGE_H_
+#define ANDROID_WEBVIEW_BROWSER_AW_QUOTA_MANAGER_BRIDGE_H_
+
+namespace android_webview {
+
+// Empty base class so this can be owned and destroyed by AwBrowserContext.
+class AwQuotaManagerBridge {
+ public:
+ virtual ~AwQuotaManagerBridge();
+};
+
+} // namespace android_webview
+
+#endif // ANDROID_WEBVIEW_BROWSER_AW_QUOTA_MANAGER_BRIDGE_H_
diff --git a/android_webview/browser/aw_quota_permission_context.cc b/android_webview/browser/aw_quota_permission_context.cc
index ce3a2c3..544edbc 100644
--- a/android_webview/browser/aw_quota_permission_context.cc
+++ b/android_webview/browser/aw_quota_permission_context.cc
@@ -23,14 +23,10 @@ void AwQuotaPermissionContext::RequestQuotaPermission(
int render_process_id,
int render_view_id,
const PermissionCallback& callback) {
- if (type != quota::kStorageTypePersistent) {
- callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
- } else {
- // TODO(boliu): Implement this to power
- // WebChromeClient.onExceededDatabaseQuota
- NOTIMPLEMENTED();
- callback.Run(QUOTA_PERMISSION_RESPONSE_CANCELLED);
- }
+ // Android WebView only uses quota::kStorageTypeTemporary type of storage
+ // with quota managed automatically, not through this interface. Therefore
+ // unconditionally disallow all quota requests here.
+ callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
}
} // namespace android_webview
diff --git a/android_webview/browser/jni_dependency_factory.h b/android_webview/browser/jni_dependency_factory.h
new file mode 100644
index 0000000..4adcc25
--- /dev/null
+++ b/android_webview/browser/jni_dependency_factory.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 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.
+
+#ifndef ANDROID_WEBVIEW_BROWSER_JNI_DEPENDENCY_FACTORY_H_
+#define ANDROID_WEBVIEW_BROWSER_JNI_DEPENDENCY_FACTORY_H_
+
+namespace content {
+class GeolocationPermissionContext;
+class WebContents;
+class WebContentsViewDelegate;
+} // namespace content
+
+namespace android_webview {
+
+class AwBrowserContext;
+class AwQuotaManagerBridge;
+
+// Used to create instances of objects under native that are used in browser.
+class JniDependencyFactory {
+ public:
+ virtual ~JniDependencyFactory() {}
+
+ virtual AwQuotaManagerBridge* CreateAwQuotaManagerBridge(
+ AwBrowserContext* browser_context) = 0;
+ virtual content::GeolocationPermissionContext* CreateGeolocationPermission(
+ AwBrowserContext* browser_context) = 0;
+ virtual content::WebContentsViewDelegate* CreateViewDelegate(
+ content::WebContents* web_contents) = 0;
+};
+
+} // namespace android_webview
+
+#endif // ANDROID_WEBVIEW_BROWSER_JNI_DEPENDENCY_FACTORY_H_
diff --git a/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java b/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java
new file mode 100644
index 0000000..6e94134
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/AwQuotaManagerBridge.java
@@ -0,0 +1,162 @@
+// Copyright (c) 2013 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.
+
+package org.chromium.android_webview;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.ThreadUtils;
+
+import android.webkit.ValueCallback;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Bridge between android.webview.WebStorage and native QuotaManager. This object is owned by Java
+ * AwBrowserContext and the native side is owned by the native AwBrowserContext.
+ *
+ * TODO(boliu): Actually make this true after Java AwBrowserContext is added.
+ */
+@JNINamespace("android_webview")
+public class AwQuotaManagerBridge {
+ // TODO(boliu): This should be obtained from Java AwBrowserContext that owns this.
+ private static native int nativeGetDefaultNativeAwQuotaManagerBridge();
+
+ // TODO(boliu): This should be owned by Java AwBrowserContext, not a singleton.
+ private static AwQuotaManagerBridge sInstance;
+ public static AwQuotaManagerBridge getInstance() {
+ ThreadUtils.assertOnUiThread();
+ if (sInstance == null) {
+ sInstance = new AwQuotaManagerBridge(nativeGetDefaultNativeAwQuotaManagerBridge());
+ }
+ return sInstance;
+ }
+
+ /**
+ * This class represent the callback value of android.webview.WebStorage.getOrigins. The values
+ * are optimized for JNI convenience and need to be converted.
+ */
+ public static class Origins {
+ // Origin, usage, and quota data in parallel arrays of same length.
+ public final String[] mOrigins;
+ public final long[] mUsages;
+ public final long[] mQuotas;
+
+ Origins(String[] origins, long[] usages, long[] quotas) {
+ mOrigins = origins;
+ mUsages = usages;
+ mQuotas = quotas;
+ }
+ }
+
+ // This is not owning. The native object is owned by the native AwBrowserContext.
+ private int mNativeAwQuotaManagerBridgeImpl;
+
+ // The Java callbacks are saved here. An incrementing callback id is generated for each saved
+ // callback and is passed to the native side to identify callback.
+ private int mNextId;
+ private Map<Integer, ValueCallback<Origins>> mPendingGetOriginCallbacks;
+ private Map<Integer, ValueCallback<Long>> mPendingGetQuotaForOriginCallbacks;
+ private Map<Integer, ValueCallback<Long>> mPendingGetUsageForOriginCallbacks;
+
+ private AwQuotaManagerBridge(int nativeAwQuotaManagerBridgeImpl) {
+ mNativeAwQuotaManagerBridgeImpl = nativeAwQuotaManagerBridgeImpl;
+ mPendingGetOriginCallbacks =
+ new HashMap<Integer, ValueCallback<Origins>>();
+ mPendingGetQuotaForOriginCallbacks = new HashMap<Integer, ValueCallback<Long>>();
+ mPendingGetUsageForOriginCallbacks = new HashMap<Integer, ValueCallback<Long>>();
+ nativeInit(mNativeAwQuotaManagerBridgeImpl);
+ }
+
+ private int getNextId() {
+ ThreadUtils.assertOnUiThread();
+ return ++mNextId;
+ }
+
+ /*
+ * There are five HTML5 offline storage APIs.
+ * 1) Web Storage (ie the localStorage and sessionStorage variables)
+ * 2) Web SQL database
+ * 3) Application cache
+ * 4) Indexed Database
+ * 5) Filesystem API
+ */
+
+ /**
+ * Implements WebStorage.deleteAllData(). Clear the storage of all five offline APIs.
+ *
+ * TODO(boliu): Actually clear Web Storage.
+ */
+ public void deleteAllData() {
+ nativeDeleteAllData(mNativeAwQuotaManagerBridgeImpl);
+ }
+
+ /**
+ * Implements WebStorage.deleteOrigin(). Clear the storage of APIs 2-5 for the given origin.
+ */
+ public void deleteOrigin(String origin) {
+ nativeDeleteOrigin(mNativeAwQuotaManagerBridgeImpl, origin);
+ }
+
+ /**
+ * Implements WebStorage.getOrigins. Get the per origin usage and quota of APIs 2-5 in
+ * aggregate.
+ */
+ public void getOrigins(ValueCallback<Origins> callback) {
+ int callbackId = getNextId();
+ assert !mPendingGetOriginCallbacks.containsKey(callbackId);
+ mPendingGetOriginCallbacks.put(callbackId, callback);
+ nativeGetOrigins(mNativeAwQuotaManagerBridgeImpl, callbackId);
+ }
+
+ /**
+ * Implements WebStorage.getQuotaForOrigin. Get the quota of APIs 2-5 in aggregate for given
+ * origin.
+ */
+ public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
+ int callbackId = getNextId();
+ assert !mPendingGetQuotaForOriginCallbacks.containsKey(callbackId);
+ mPendingGetQuotaForOriginCallbacks.put(callbackId, callback);
+ nativeGetUsageAndQuotaForOrigin(mNativeAwQuotaManagerBridgeImpl, origin, callbackId, true);
+ }
+
+ /**
+ * Implements WebStorage.getUsageForOrigin. Get the usage of APIs 2-5 in aggregate for given
+ * origin.
+ */
+ public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
+ int callbackId = getNextId();
+ assert !mPendingGetUsageForOriginCallbacks.containsKey(callbackId);
+ mPendingGetUsageForOriginCallbacks.put(callbackId, callback);
+ nativeGetUsageAndQuotaForOrigin(mNativeAwQuotaManagerBridgeImpl, origin, callbackId, false);
+ }
+
+ @CalledByNative
+ private void onGetOriginsCallback(int callbackId, String[] origin, long[] usages,
+ long[] quotas) {
+ assert mPendingGetOriginCallbacks.containsKey(callbackId);
+ mPendingGetOriginCallbacks.remove(callbackId).onReceiveValue(
+ new Origins(origin, usages, quotas));
+ }
+
+ @CalledByNative
+ private void onGetUsageAndQuotaForOriginCallback(
+ int callbackId, boolean isQuota, long usage, long quota) {
+ if (isQuota) {
+ assert mPendingGetQuotaForOriginCallbacks.containsKey(callbackId);
+ mPendingGetQuotaForOriginCallbacks.remove(callbackId).onReceiveValue(quota);
+ } else {
+ assert mPendingGetUsageForOriginCallbacks.containsKey(callbackId);
+ mPendingGetUsageForOriginCallbacks.remove(callbackId).onReceiveValue(usage);
+ }
+ }
+
+ private native void nativeInit(int nativeAwQuotaManagerBridgeImpl);
+ private native void nativeDeleteAllData(int nativeAwQuotaManagerBridgeImpl);
+ private native void nativeDeleteOrigin(int nativeAwQuotaManagerBridgeImpl, String origin);
+ private native void nativeGetOrigins(int nativeAwQuotaManagerBridgeImpl, int callbackId);
+ private native void nativeGetUsageAndQuotaForOrigin(int nativeAwQuotaManagerBridgeImpl,
+ String origin, int callbackId, boolean isQuota);
+}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java
new file mode 100644
index 0000000..c5e56de
--- /dev/null
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java
@@ -0,0 +1,291 @@
+// Copyright (c) 2013 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.
+
+package org.chromium.android_webview.test;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Pair;
+import android.webkit.ValueCallback;
+
+import org.chromium.android_webview.AwContents;
+import org.chromium.android_webview.AwQuotaManagerBridge;
+import org.chromium.base.test.util.Feature;
+import org.chromium.content.browser.ContentSettings;
+import org.chromium.content.browser.test.util.CallbackHelper;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.net.test.util.TestWebServer;
+
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.List;
+
+public class AwQuotaManagerBridgeTest extends AndroidWebViewTestBase {
+ private TestAwContentsClient mContentsClient;
+ private AwTestContainerView mTestView;
+ private AwContents mAwContents;
+ private TestWebServer mWebServer;
+ private String mOrigin;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mContentsClient = new TestAwContentsClient();
+ mTestView = createAwTestContainerViewOnMainSync(mContentsClient);
+ mAwContents = mTestView.getAwContents();
+ mWebServer = new TestWebServer(false);
+ mOrigin = mWebServer.getBaseUrl();
+
+ ContentSettings settings = getContentSettingsOnUiThread(mAwContents);
+ settings.setJavaScriptEnabled(true);
+ settings.setDomStorageEnabled(true);
+ settings.setAppCacheEnabled(true);
+ settings.setAppCachePath("whatever"); // Enables AppCache.
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ deleteAllData();
+ if (mWebServer != null) {
+ mWebServer.shutdown();
+ }
+ super.tearDown();
+ }
+
+ private AwQuotaManagerBridge getQuotaManagerBridge() throws Exception {
+ return runTestOnUiThreadAndGetResult(new Callable<AwQuotaManagerBridge>() {
+ @Override
+ public AwQuotaManagerBridge call() throws Exception {
+ return AwQuotaManagerBridge.getInstance();
+ }
+ });
+ }
+
+ private void deleteAllData() throws Exception {
+ final AwQuotaManagerBridge bridge = getQuotaManagerBridge();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ bridge.deleteAllData();
+ }
+ });
+ }
+
+ private void deleteOrigin(final String origin) throws Exception {
+ final AwQuotaManagerBridge bridge = getQuotaManagerBridge();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ bridge.deleteOrigin(origin);
+ }
+ });
+ }
+
+ private static class GetOriginsCallbackHelper extends CallbackHelper {
+ private AwQuotaManagerBridge.Origins mOrigins;
+
+ public void notifyCalled(AwQuotaManagerBridge.Origins origins) {
+ mOrigins = origins;
+ notifyCalled();
+ }
+
+ public AwQuotaManagerBridge.Origins getOrigins() {
+ assert mCallCount > 0;
+ return mOrigins;
+ }
+ }
+
+ private AwQuotaManagerBridge.Origins getOrigins() throws Exception {
+ final GetOriginsCallbackHelper callbackHelper = new GetOriginsCallbackHelper();
+ final AwQuotaManagerBridge bridge = getQuotaManagerBridge();
+
+ int callCount = callbackHelper.getCallCount();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ bridge.getOrigins(
+ new ValueCallback<AwQuotaManagerBridge.Origins>() {
+ @Override
+ public void onReceiveValue(AwQuotaManagerBridge.Origins origins) {
+ callbackHelper.notifyCalled(origins);
+ }
+ }
+ );
+ }
+ });
+ callbackHelper.waitForCallback(callCount);
+
+ return callbackHelper.getOrigins();
+ }
+
+ private static class LongValueCallbackHelper extends CallbackHelper {
+ private long mValue;
+
+ public void notifyCalled(long value) {
+ mValue = value;
+ notifyCalled();
+ }
+
+ public long getValue() {
+ assert mCallCount > 0;
+ return mValue;
+ }
+ }
+
+ private long getQuotaForOrigin(final String origin) throws Exception {
+ final LongValueCallbackHelper callbackHelper = new LongValueCallbackHelper();
+ final AwQuotaManagerBridge bridge = getQuotaManagerBridge();
+
+ int callCount = callbackHelper.getCallCount();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ bridge.getQuotaForOrigin("foo.com",
+ new ValueCallback<Long>() {
+ @Override
+ public void onReceiveValue(Long quota) {
+ callbackHelper.notifyCalled(quota);
+ }
+ }
+ );
+ }
+ });
+ callbackHelper.waitForCallback(callCount);
+
+ return callbackHelper.getValue();
+ }
+
+ private long getUsageForOrigin(final String origin) throws Exception {
+ final LongValueCallbackHelper callbackHelper = new LongValueCallbackHelper();
+ final AwQuotaManagerBridge bridge = getQuotaManagerBridge();
+
+ int callCount = callbackHelper.getCallCount();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ bridge.getUsageForOrigin(origin,
+ new ValueCallback<Long>() {
+ @Override
+ public void onReceiveValue(Long usage) {
+ callbackHelper.notifyCalled(usage);
+ }
+ }
+ );
+ }
+ });
+ callbackHelper.waitForCallback(callCount);
+
+ return callbackHelper.getValue();
+ }
+
+ private void useAppCache() throws Exception {
+ final String CACHED_FILE_PATH = "/foo.js";
+ final String CACHED_FILE_CONTENTS = "1 + 1;";
+ mWebServer.setResponse(CACHED_FILE_PATH, CACHED_FILE_CONTENTS, null);
+
+ final String MANIFEST_PATH = "/foo.manifest";
+ final String MANIFEST_CONTENTS = "CACHE MANIFEST\nCACHE:\n" + CACHED_FILE_PATH;
+ List<Pair<String, String>> manifestHeaders = new ArrayList<Pair<String, String>>();
+ manifestHeaders.add(Pair.create("Content-Disposition", "text/cache-manifest"));
+ mWebServer.setResponse(MANIFEST_PATH, MANIFEST_CONTENTS, manifestHeaders);
+
+ final String PAGE_PATH = "/appcache.html";
+ final String PAGE_CONTENTS = "<html manifest=\"" + MANIFEST_PATH + "\">" +
+ "<head><script src=\"" + CACHED_FILE_PATH + "\"></script></head></html>";
+ String url = mWebServer.setResponse(PAGE_PATH, PAGE_CONTENTS, null);
+
+ loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
+ executeJavaScriptAndWaitForResult(mAwContents, mContentsClient,
+ "window.applicationCache.update();");
+ }
+
+ @LargeTest
+ @Feature({"AndroidWebView", "WebStore"})
+ public void testDeleteAllWithAppCache() throws Exception {
+ long currentUsage = getUsageForOrigin(mOrigin);
+ assertEquals(0, currentUsage);
+
+ useAppCache();
+ assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ try {
+ return getUsageForOrigin(mOrigin) > 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ }));
+
+ deleteAllData();
+ assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ try {
+ return getUsageForOrigin(mOrigin) == 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ }));
+ }
+
+ @LargeTest
+ @Feature({"AndroidWebView", "WebStore"})
+ public void testDeleteOriginWithAppCache() throws Exception {
+ long currentUsage = getUsageForOrigin(mOrigin);
+ assertEquals(0, currentUsage);
+
+ useAppCache();
+ assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ try {
+ return getUsageForOrigin(mOrigin) > 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ }));
+
+ deleteOrigin(mOrigin);
+ assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ try {
+ return getUsageForOrigin(mOrigin) == 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ }));
+ }
+
+ @LargeTest
+ @Feature({"AndroidWebView", "WebStore"})
+ public void testGetResultsMatch() throws Exception {
+ useAppCache();
+
+ CriteriaHelper.pollForCriteria(new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ try {
+ return getOrigins().mOrigins.length > 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ });
+
+ AwQuotaManagerBridge.Origins origins = getOrigins();
+ assertEquals(origins.mOrigins.length, origins.mUsages.length);
+ assertEquals(origins.mOrigins.length, origins.mQuotas.length);
+
+ for (int i = 0; i < origins.mOrigins.length; ++i) {
+ assertEquals(origins.mUsages[i], getUsageForOrigin(origins.mOrigins[i]));
+ assertEquals(origins.mQuotas[i], getQuotaForOrigin(origins.mOrigins[i]));
+ }
+ }
+}
diff --git a/android_webview/lib/aw_browser_dependency_factory_impl.cc b/android_webview/lib/aw_browser_dependency_factory_impl.cc
index bcff32f..200df11 100644
--- a/android_webview/lib/aw_browser_dependency_factory_impl.cc
+++ b/android_webview/lib/aw_browser_dependency_factory_impl.cc
@@ -4,6 +4,7 @@
#include "android_webview/lib/aw_browser_dependency_factory_impl.h"
+#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_content_browser_client.h"
#include "base/lazy_instance.h"
#include "content/public/browser/content_browser_client.h"
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index 2a8954f..aa220ea 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -7,6 +7,7 @@
#include "android_webview/browser/aw_content_browser_client.h"
#include "android_webview/lib/aw_browser_dependency_factory_impl.h"
#include "android_webview/native/aw_geolocation_permission_context.h"
+#include "android_webview/native/aw_quota_manager_bridge_impl.h"
#include "android_webview/native/aw_web_contents_view_delegate.h"
#include "android_webview/renderer/aw_content_renderer_client.h"
#include "base/command_line.h"
@@ -69,11 +70,7 @@ void AwMainDelegate::ProcessExiting(const std::string& process_type) {
content::ContentBrowserClient*
AwMainDelegate::CreateContentBrowserClient() {
- content_browser_client_.reset(
- new AwContentBrowserClient(
- &AwWebContentsViewDelegate::Create,
- &AwGeolocationPermissionContext::Create));
-
+ content_browser_client_.reset(new AwContentBrowserClient(this));
return content_browser_client_.get();
}
@@ -83,4 +80,20 @@ content::ContentRendererClient*
return content_renderer_client_.get();
}
+AwQuotaManagerBridge* AwMainDelegate::CreateAwQuotaManagerBridge(
+ AwBrowserContext* browser_context) {
+ return new AwQuotaManagerBridgeImpl(browser_context);
+}
+
+content::GeolocationPermissionContext*
+ AwMainDelegate::CreateGeolocationPermission(
+ AwBrowserContext* browser_context) {
+ return AwGeolocationPermissionContext::Create(browser_context);
+}
+
+content::WebContentsViewDelegate* AwMainDelegate::CreateViewDelegate(
+ content::WebContents* web_contents) {
+ return AwWebContentsViewDelegate::Create(web_contents);
+}
+
} // namespace android_webview
diff --git a/android_webview/lib/main/aw_main_delegate.h b/android_webview/lib/main/aw_main_delegate.h
index 92de20c..81ebccf 100644
--- a/android_webview/lib/main/aw_main_delegate.h
+++ b/android_webview/lib/main/aw_main_delegate.h
@@ -5,6 +5,7 @@
#ifndef ANDROID_WEBVIEW_LIB_MAIN_AW_MAIN_DELEGATE_H_
#define ANDROID_WEBVIEW_LIB_MAIN_AW_MAIN_DELEGATE_H_
+#include "android_webview/browser/jni_dependency_factory.h"
#include "android_webview/common/aw_content_client.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/app/content_main_delegate.h"
@@ -19,7 +20,8 @@ class AwContentBrowserClient;
class AwContentRendererClient;
// Android WebView implementation of ContentMainDelegate.
-class AwMainDelegate : public content::ContentMainDelegate {
+class AwMainDelegate : public content::ContentMainDelegate,
+ public JniDependencyFactory {
public:
AwMainDelegate();
virtual ~AwMainDelegate();
@@ -37,6 +39,14 @@ class AwMainDelegate : public content::ContentMainDelegate {
virtual content::ContentRendererClient*
CreateContentRendererClient() OVERRIDE;
+ // JniDependencyFactory implementation.
+ virtual AwQuotaManagerBridge* CreateAwQuotaManagerBridge(
+ AwBrowserContext* browser_context) OVERRIDE;
+ virtual content::GeolocationPermissionContext* CreateGeolocationPermission(
+ AwBrowserContext* browser_context) OVERRIDE;
+ virtual content::WebContentsViewDelegate* CreateViewDelegate(
+ content::WebContents* web_contents) OVERRIDE;
+
scoped_ptr<content::BrowserMainRunner> browser_runner_;
AwContentClient content_client_;
scoped_ptr<AwContentBrowserClient> content_browser_client_;
diff --git a/android_webview/native/android_webview_jni_registrar.cc b/android_webview/native/android_webview_jni_registrar.cc
index 47c7373..0090220 100644
--- a/android_webview/native/android_webview_jni_registrar.cc
+++ b/android_webview/native/android_webview_jni_registrar.cc
@@ -8,6 +8,7 @@
#include "android_webview/native/aw_contents.h"
#include "android_webview/native/aw_contents_io_thread_client_impl.h"
#include "android_webview/native/aw_http_auth_handler.h"
+#include "android_webview/native/aw_quota_manager_bridge_impl.h"
#include "android_webview/native/aw_resource.h"
#include "android_webview/native/aw_settings.h"
#include "android_webview/native/aw_web_contents_delegate.h"
@@ -28,6 +29,7 @@ static base::android::RegistrationMethod kWebViewRegisteredMethods[] = {
{ "AwContentsIoThreadClientImpl", RegisterAwContentsIoThreadClientImpl},
{ "AwSettings", RegisterAwSettings },
{ "AwHttpAuthHandler", RegisterAwHttpAuthHandler },
+ { "AwQuotaManagerBridge", RegisterAwQuotaManagerBridge },
{ "AwResource", AwResource::RegisterAwResource },
{ "AwWebContentsDelegate", RegisterAwWebContentsDelegate },
{ "CookieManager", RegisterCookieManager },
diff --git a/android_webview/native/aw_geolocation_permission_context.cc b/android_webview/native/aw_geolocation_permission_context.cc
index 3b67862..3c2481c 100644
--- a/android_webview/native/aw_geolocation_permission_context.cc
+++ b/android_webview/native/aw_geolocation_permission_context.cc
@@ -56,7 +56,7 @@ AwGeolocationPermissionContext::RequestGeolocationPermission(
// static
content::GeolocationPermissionContext*
-AwGeolocationPermissionContext::Create() {
+AwGeolocationPermissionContext::Create(AwBrowserContext* browser_context) {
return new AwGeolocationPermissionContext();
}
diff --git a/android_webview/native/aw_geolocation_permission_context.h b/android_webview/native/aw_geolocation_permission_context.h
index 9e1cf53..4596708 100644
--- a/android_webview/native/aw_geolocation_permission_context.h
+++ b/android_webview/native/aw_geolocation_permission_context.h
@@ -11,10 +11,13 @@ class GURL;
namespace android_webview {
+class AwBrowserContext;
+
class AwGeolocationPermissionContext :
public content::GeolocationPermissionContext {
public:
- static content::GeolocationPermissionContext* Create();
+ static content::GeolocationPermissionContext* Create(
+ AwBrowserContext* browser_context);
// content::GeolocationPermissionContext implementation
virtual void RequestGeolocationPermission(
diff --git a/android_webview/native/aw_quota_manager_bridge_impl.cc b/android_webview/native/aw_quota_manager_bridge_impl.cc
new file mode 100644
index 0000000..83fdb60
--- /dev/null
+++ b/android_webview/native/aw_quota_manager_bridge_impl.cc
@@ -0,0 +1,337 @@
+// Copyright (c) 2013 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.
+
+#include "android_webview/native/aw_quota_manager_bridge_impl.h"
+
+#include <set>
+
+#include "android_webview/browser/aw_browser_context.h"
+#include "android_webview/browser/aw_content_browser_client.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_client.h"
+#include "googleurl/src/gurl.h"
+#include "jni/AwQuotaManagerBridge_jni.h"
+#include "webkit/quota/quota_manager.h"
+#include "webkit/quota/quota_types.h"
+
+using base::android::AttachCurrentThread;
+using content::BrowserThread;
+using content::StoragePartition;
+using quota::QuotaClient;
+using quota::QuotaManager;
+
+namespace android_webview {
+
+namespace {
+
+// This object lives on UI and IO threads. Care need to be taken to make sure
+// there are no concurrent accesses to instance variables. Also this object
+// is refcounted in the various callbacks, and is destroyed when all callbacks
+// are destroyed at the end of DoneOnUIThread.
+class GetOriginsTask : public base::RefCountedThreadSafe<GetOriginsTask> {
+ public:
+ GetOriginsTask(
+ const AwQuotaManagerBridgeImpl::GetOriginsCallback& callback,
+ QuotaManager* quota_manager);
+
+ void Run();
+
+ private:
+ friend class base::RefCountedThreadSafe<GetOriginsTask>;
+ ~GetOriginsTask();
+
+ void OnOriginsObtained(const std::set<GURL>& origins,
+ quota::StorageType type);
+
+ void OnUsageAndQuotaObtained(const GURL& origin,
+ quota::QuotaStatusCode status_code,
+ int64 usage,
+ int64 quota);
+
+ void CheckDone();
+ void DoneOnUIThread();
+
+ AwQuotaManagerBridgeImpl::GetOriginsCallback ui_callback_;
+ scoped_refptr<QuotaManager> quota_manager_;
+
+ std::vector<std::string> origin_;
+ std::vector<int64> usage_;
+ std::vector<int64> quota_;
+
+ size_t num_callbacks_to_wait_;
+ size_t num_callbacks_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetOriginsTask);
+};
+
+GetOriginsTask::GetOriginsTask(
+ const AwQuotaManagerBridgeImpl::GetOriginsCallback& callback,
+ QuotaManager* quota_manager)
+ : ui_callback_(callback),
+ quota_manager_(quota_manager) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+GetOriginsTask::~GetOriginsTask() {}
+
+void GetOriginsTask::Run() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&QuotaManager::GetOriginsModifiedSince,
+ quota_manager_,
+ quota::kStorageTypeTemporary,
+ base::Time() /* Since beginning of time. */,
+ base::Bind(&GetOriginsTask::OnOriginsObtained, this)));
+}
+
+void GetOriginsTask::OnOriginsObtained(
+ const std::set<GURL>& origins, quota::StorageType type) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ num_callbacks_to_wait_ = origins.size();
+ num_callbacks_received_ = 0u;
+
+ for (std::set<GURL>::const_iterator origin = origins.begin();
+ origin != origins.end();
+ ++origin) {
+ quota_manager_->GetUsageAndQuota(
+ *origin,
+ type,
+ base::Bind(&GetOriginsTask::OnUsageAndQuotaObtained, this, *origin));
+ }
+
+ CheckDone();
+}
+
+void GetOriginsTask::OnUsageAndQuotaObtained(const GURL& origin,
+ quota::QuotaStatusCode status_code,
+ int64 usage,
+ int64 quota) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (status_code == quota::kQuotaStatusOk) {
+ origin_.push_back(origin.spec());
+ usage_.push_back(usage);
+ quota_.push_back(quota);
+ }
+
+ ++num_callbacks_received_;
+ CheckDone();
+}
+
+void GetOriginsTask::CheckDone() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (num_callbacks_received_ == num_callbacks_to_wait_) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&GetOriginsTask::DoneOnUIThread, this));
+ } else if (num_callbacks_received_ > num_callbacks_to_wait_) {
+ NOTREACHED();
+ }
+}
+
+// This method is to avoid copying the 3 vector arguments into a bound callback.
+void GetOriginsTask::DoneOnUIThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ui_callback_.Run(origin_, usage_, quota_);
+}
+
+} // namespace
+
+
+// static
+jint GetDefaultNativeAwQuotaManagerBridge(JNIEnv* env, jclass clazz) {
+ content::ContentBrowserClient* browser_client =
+ content::GetContentClient()->browser();
+ DCHECK(browser_client);
+
+ AwContentBrowserClient* aw_browser_client =
+ AwContentBrowserClient::FromContentBrowserClient(browser_client);
+ AwBrowserContext* browser_context = aw_browser_client->GetAwBrowserContext();
+ DCHECK(browser_context);
+
+ AwQuotaManagerBridgeImpl* bridge = static_cast<AwQuotaManagerBridgeImpl*>(
+ browser_context->GetQuotaManagerBridge());
+ DCHECK(bridge);
+ return reinterpret_cast<jint>(bridge);
+}
+
+AwQuotaManagerBridgeImpl::AwQuotaManagerBridgeImpl(
+ AwBrowserContext* browser_context)
+ : weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ browser_context_(browser_context) {
+}
+
+AwQuotaManagerBridgeImpl::~AwQuotaManagerBridgeImpl() {}
+
+void AwQuotaManagerBridgeImpl::Init(JNIEnv* env, jobject object) {
+ java_ref_ = JavaObjectWeakGlobalRef(env, object);
+}
+
+QuotaManager* AwQuotaManagerBridgeImpl::GetQuotaManager() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // AndroidWebview does not use per-site storage partitions.
+ StoragePartition* storage_partition =
+ content::BrowserContext::GetStoragePartitionForSite(
+ browser_context_, GURL());
+ DCHECK(storage_partition);
+
+ QuotaManager* quota_manager = storage_partition->GetQuotaManager();
+ DCHECK(quota_manager);
+ return quota_manager;
+}
+
+namespace {
+
+void IgnoreStatus(quota::QuotaStatusCode status_code) {}
+
+void DeleteAllOriginData(
+ QuotaManager* quota_manager,
+ const std::set<GURL>& origins,
+ quota::StorageType type) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ for (std::set<GURL>::const_iterator origin = origins.begin();
+ origin != origins.end();
+ ++origin) {
+ quota_manager->DeleteOriginData(*origin,
+ type,
+ QuotaClient::kAllClientsMask,
+ base::Bind(&IgnoreStatus));
+ }
+}
+
+} // namespace
+
+// Cannot directly call StoragePartition clear data methods because cookies are
+// controlled separately.
+// TODO(boliu): Should consider dedup delete code with StoragePartition.
+void AwQuotaManagerBridgeImpl::DeleteAllData(JNIEnv* env, jobject object) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scoped_refptr<QuotaManager> quota_manager = GetQuotaManager();
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&QuotaManager::GetOriginsModifiedSince,
+ quota_manager,
+ quota::kStorageTypeTemporary,
+ base::Time() /* Since beginning of time. */,
+ base::Bind(&DeleteAllOriginData, quota_manager)));
+
+ // TODO(boliu): This needs to clear WebStorage (ie localStorage and
+ // sessionStorage).
+}
+
+void AwQuotaManagerBridgeImpl::DeleteOrigin(
+ JNIEnv* env, jobject object, jstring origin) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&QuotaManager::DeleteOriginData,
+ GetQuotaManager(),
+ GURL(base::android::ConvertJavaStringToUTF16(env, origin)),
+ quota::kStorageTypeTemporary,
+ QuotaClient::kAllClientsMask,
+ base::Bind(&IgnoreStatus)));
+}
+
+void AwQuotaManagerBridgeImpl::GetOrigins(
+ JNIEnv* env, jobject object, jint callback_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // TODO(boliu): Consider expanding QuotaManager::GetUsageInfo to include
+ // quota so can be used here.
+
+ const GetOriginsCallback ui_callback = base::Bind(
+ &AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl,
+ weak_factory_.GetWeakPtr(),
+ callback_id);
+
+ (new GetOriginsTask(ui_callback, GetQuotaManager()))->Run();
+}
+
+void AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl(
+ int jcallback_id,
+ const std::vector<std::string>& origin,
+ const std::vector<int64>& usage,
+ const std::vector<int64>& quota) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ Java_AwQuotaManagerBridge_onGetOriginsCallback(
+ env,
+ obj.obj(),
+ jcallback_id,
+ base::android::ToJavaArrayOfStrings(env, origin).obj(),
+ base::android::ToJavaLongArray(env, usage).obj(),
+ base::android::ToJavaLongArray(env, quota).obj());
+}
+
+namespace {
+
+void OnUsageAndQuotaObtained(
+ const AwQuotaManagerBridgeImpl::QuotaUsageCallback& ui_callback,
+ quota::QuotaStatusCode status_code,
+ int64 usage,
+ int64 quota) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (status_code != quota::kQuotaStatusOk) {
+ usage = 0;
+ quota = 0;
+ }
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(ui_callback, usage, quota));
+}
+
+} // namespace
+
+void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOrigin(
+ JNIEnv* env, jobject object,
+ jstring origin,
+ jint callback_id,
+ bool is_quota) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const QuotaUsageCallback ui_callback = base::Bind(
+ &AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl,
+ weak_factory_.GetWeakPtr(),
+ callback_id,
+ is_quota);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&QuotaManager::GetUsageAndQuota,
+ GetQuotaManager(),
+ GURL(base::android::ConvertJavaStringToUTF16(env, origin)),
+ quota::kStorageTypeTemporary,
+ base::Bind(&OnUsageAndQuotaObtained, ui_callback)));
+}
+
+void AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl(
+ int jcallback_id, bool is_quota, int64 usage, int64 quota) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return;
+
+ Java_AwQuotaManagerBridge_onGetUsageAndQuotaForOriginCallback(
+ env, obj.obj(), jcallback_id, is_quota, usage, quota);
+}
+
+bool RegisterAwQuotaManagerBridge(JNIEnv* env) {
+ return RegisterNativesImpl(env) >= 0;
+}
+
+} // namespace android_webview
diff --git a/android_webview/native/aw_quota_manager_bridge_impl.h b/android_webview/native/aw_quota_manager_bridge_impl.h
new file mode 100644
index 0000000..a776949
--- /dev/null
+++ b/android_webview/native/aw_quota_manager_bridge_impl.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2013 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.
+
+#ifndef ANDROID_WEBVIEW_NATIVE_AW_QUOTA_MANAGER_BRIDGE_IMPL_H_
+#define ANDROID_WEBVIEW_NATIVE_AW_QUOTA_MANAGER_BRIDGE_IMPL_H_
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+#include "android_webview/browser/aw_quota_manager_bridge.h"
+#include "base/android/jni_helper.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+class GURL;
+
+namespace quota {
+class QuotaManager;
+} // namespace quota
+
+namespace android_webview {
+
+class AwBrowserContext;
+
+class AwQuotaManagerBridgeImpl : public AwQuotaManagerBridge {
+ public:
+ explicit AwQuotaManagerBridgeImpl(AwBrowserContext* browser_context);
+ virtual ~AwQuotaManagerBridgeImpl();
+
+ // Called by Java.
+ void Init(JNIEnv* env, jobject object);
+ void DeleteAllData(JNIEnv* env, jobject object);
+ void DeleteOrigin(JNIEnv* env, jobject object, jstring origin);
+ void GetOrigins(JNIEnv* env, jobject object, jint callback_id);
+ void GetUsageAndQuotaForOrigin(JNIEnv* env,
+ jobject object,
+ jstring origin,
+ jint callback_id,
+ bool is_quota);
+
+ typedef base::Callback<
+ void(const std::vector<std::string>& /* origin */,
+ const std::vector<int64>& /* usage */,
+ const std::vector<int64>& /* quota */)> GetOriginsCallback;
+ typedef base::Callback<void(int64 /* usage */,
+ int64 /* quota */)> QuotaUsageCallback;
+
+ private:
+ quota::QuotaManager* GetQuotaManager() const;
+
+ void GetOriginsCallbackImpl(
+ int jcallback_id,
+ const std::vector<std::string>& origin,
+ const std::vector<int64>& usage,
+ const std::vector<int64>& quota);
+ void QuotaUsageCallbackImpl(
+ int jcallback_id, bool is_quota, int64 usage, int64 quota);
+
+ base::WeakPtrFactory<AwQuotaManagerBridgeImpl> weak_factory_;
+ AwBrowserContext* browser_context_;
+ JavaObjectWeakGlobalRef java_ref_;
+
+ DISALLOW_COPY_AND_ASSIGN(AwQuotaManagerBridgeImpl);
+};
+
+bool RegisterAwQuotaManagerBridge(JNIEnv* env);
+
+} // namespace android_webview
+
+#endif // ANDROID_WEBVIEW_NATIVE_AW_QUOTA_MANAGER_BRIDGE_IMPL_H_
diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp
index cb9562a..3f4f84e 100644
--- a/android_webview/native/webview_native.gyp
+++ b/android_webview/native/webview_native.gyp
@@ -37,6 +37,8 @@
'aw_http_auth_handler.h',
'aw_javascript_dialog_manager.cc',
'aw_javascript_dialog_manager.h',
+ 'aw_quota_manager_bridge_impl.cc',
+ 'aw_quota_manager_bridge_impl.h',
'aw_resource.cc',
'aw_resource.h',
'aw_settings.cc',
@@ -79,6 +81,7 @@
'../java/src/org/chromium/android_webview/AwContentsIoThreadClient.java',
'../java/src/org/chromium/android_webview/AwCookieManager.java',
'../java/src/org/chromium/android_webview/AwHttpAuthHandler.java',
+ '../java/src/org/chromium/android_webview/AwQuotaManagerBridge.java',
'../java/src/org/chromium/android_webview/AwResource.java',
'../java/src/org/chromium/android_webview/AwSettings.java',
'../java/src/org/chromium/android_webview/AwWebContentsDelegate.java',
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index fe2aadb..596914b 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -25,6 +25,26 @@ ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
}
+ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+ JNIEnv* env, const int64* longs, size_t len) {
+ jlongArray long_array = env->NewLongArray(len);
+ CheckException(env);
+ DCHECK(long_array);
+
+ jlong* elements = env->GetLongArrayElements(long_array, NULL);
+ memcpy(elements, longs, len * sizeof(*longs));
+ env->ReleaseLongArrayElements(long_array, elements, 0);
+ CheckException(env);
+
+ return ScopedJavaLocalRef<jlongArray>(env, long_array);
+}
+
+// Returns a new Java long array converted from the given int64 array.
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+ JNIEnv* env, const std::vector<int64>& longs) {
+ return ToJavaLongArray(env, longs.begin(), longs.size());
+}
+
ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
JNIEnv* env, const std::vector<std::string>& v) {
ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
index b5050c3..bb73ea0 100644
--- a/base/android/jni_array.h
+++ b/base/android/jni_array.h
@@ -20,6 +20,13 @@ namespace android {
BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
JNIEnv* env, const uint8* bytes, size_t len);
+// Returns a new Java long array converted from the given int64 array.
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+ JNIEnv* env, const int64* longs, size_t len);
+
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+ JNIEnv* env, const std::vector<int64>& longs);
+
// Returns a array of Java byte array converted from |v|.
BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
JNIEnv* env, const std::vector<std::string>& v);
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc
index a4e3025..bc497a8 100644
--- a/base/android/jni_array_unittest.cc
+++ b/base/android/jni_array_unittest.cc
@@ -27,6 +27,34 @@ TEST(JniArray, BasicConversions) {
EXPECT_EQ(8U, vec.size());
}
+void CheckLongConversion(
+ JNIEnv* env,
+ const int64* long_array,
+ const size_t len,
+ const ScopedJavaLocalRef<jlongArray>& longs) {
+ ASSERT_TRUE(longs.obj());
+
+ jsize java_array_len = env->GetArrayLength(longs.obj());
+ ASSERT_EQ(static_cast<int>(len), java_array_len);
+
+ jlong value;
+ for (size_t i = 0; i < len; ++i) {
+ env->GetLongArrayRegion(longs.obj(), i, 1, &value);
+ ASSERT_EQ(long_array[i], value);
+ }
+}
+
+TEST(JniArray, LongConversions) {
+ const int64 kLongs[] = { 0, 1, -1, kint64min, kint64max};
+ const size_t kLen = arraysize(kLongs);
+
+ JNIEnv* env = AttachCurrentThread();
+ CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, kLongs, kLen));
+
+ const std::vector<int64> vec(kLongs, kLongs + kLen);
+ CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec));
+}
+
TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
const int kMaxItems = 50;
JNIEnv* env = AttachCurrentThread();