1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.android_webview;
6
7import android.webkit.ValueCallback;
8
9import org.chromium.base.CalledByNative;
10import org.chromium.base.JNINamespace;
11import org.chromium.base.ThreadUtils;
12
13import java.util.HashMap;
14import java.util.Map;
15
16/**
17 * Bridge between android.webview.WebStorage and native QuotaManager. This object is owned by Java
18 * AwBrowserContext and the native side is owned by the native AwBrowserContext.
19 *
20 * TODO(boliu): Actually make this true after Java AwBrowserContext is added.
21 */
22@JNINamespace("android_webview")
23public class AwQuotaManagerBridge {
24    // TODO(boliu): This should be obtained from Java AwBrowserContext that owns this.
25    private static native long nativeGetDefaultNativeAwQuotaManagerBridge();
26
27    // TODO(boliu): This should be owned by Java AwBrowserContext, not a singleton.
28    private static AwQuotaManagerBridge sInstance;
29    public static AwQuotaManagerBridge getInstance() {
30        ThreadUtils.assertOnUiThread();
31        if (sInstance == null) {
32            sInstance = new AwQuotaManagerBridge(nativeGetDefaultNativeAwQuotaManagerBridge());
33        }
34        return sInstance;
35    }
36
37    /**
38     * This class represent the callback value of android.webview.WebStorage.getOrigins. The values
39     * are optimized for JNI convenience and need to be converted.
40     */
41    public static class Origins {
42        // Origin, usage, and quota data in parallel arrays of same length.
43        public final String[] mOrigins;
44        public final long[] mUsages;
45        public final long[] mQuotas;
46
47        Origins(String[] origins, long[] usages, long[] quotas) {
48            mOrigins = origins;
49            mUsages = usages;
50            mQuotas = quotas;
51        }
52    }
53
54    // This is not owning. The native object is owned by the native AwBrowserContext.
55    private long mNativeAwQuotaManagerBridgeImpl;
56
57    // The Java callbacks are saved here. An incrementing callback id is generated for each saved
58    // callback and is passed to the native side to identify callback.
59    private int mNextId;
60    private Map<Integer, ValueCallback<Origins>> mPendingGetOriginCallbacks;
61    private Map<Integer, ValueCallback<Long>> mPendingGetQuotaForOriginCallbacks;
62    private Map<Integer, ValueCallback<Long>> mPendingGetUsageForOriginCallbacks;
63
64    private AwQuotaManagerBridge(long nativeAwQuotaManagerBridgeImpl) {
65        mNativeAwQuotaManagerBridgeImpl = nativeAwQuotaManagerBridgeImpl;
66        mPendingGetOriginCallbacks =
67                new HashMap<Integer, ValueCallback<Origins>>();
68        mPendingGetQuotaForOriginCallbacks = new HashMap<Integer, ValueCallback<Long>>();
69        mPendingGetUsageForOriginCallbacks = new HashMap<Integer, ValueCallback<Long>>();
70        nativeInit(mNativeAwQuotaManagerBridgeImpl);
71    }
72
73    private int getNextId() {
74        ThreadUtils.assertOnUiThread();
75        return ++mNextId;
76    }
77
78    /*
79     * There are five HTML5 offline storage APIs.
80     * 1) Web Storage (ie the localStorage and sessionStorage variables)
81     * 2) Web SQL database
82     * 3) Application cache
83     * 4) Indexed Database
84     * 5) Filesystem API
85     */
86
87    /**
88     * Implements WebStorage.deleteAllData(). Clear the storage of all five offline APIs.
89     *
90     * TODO(boliu): Actually clear Web Storage.
91     */
92    public void deleteAllData() {
93        nativeDeleteAllData(mNativeAwQuotaManagerBridgeImpl);
94    }
95
96    /**
97     * Implements WebStorage.deleteOrigin(). Clear the storage of APIs 2-5 for the given origin.
98     */
99    public void deleteOrigin(String origin) {
100        nativeDeleteOrigin(mNativeAwQuotaManagerBridgeImpl, origin);
101    }
102
103    /**
104     * Implements WebStorage.getOrigins. Get the per origin usage and quota of APIs 2-5 in
105     * aggregate.
106     */
107    public void getOrigins(ValueCallback<Origins> callback) {
108        int callbackId = getNextId();
109        assert !mPendingGetOriginCallbacks.containsKey(callbackId);
110        mPendingGetOriginCallbacks.put(callbackId, callback);
111        nativeGetOrigins(mNativeAwQuotaManagerBridgeImpl, callbackId);
112    }
113
114    /**
115     * Implements WebStorage.getQuotaForOrigin. Get the quota of APIs 2-5 in aggregate for given
116     * origin.
117     */
118    public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
119        int callbackId = getNextId();
120        assert !mPendingGetQuotaForOriginCallbacks.containsKey(callbackId);
121        mPendingGetQuotaForOriginCallbacks.put(callbackId, callback);
122        nativeGetUsageAndQuotaForOrigin(mNativeAwQuotaManagerBridgeImpl, origin, callbackId, true);
123    }
124
125    /**
126     * Implements WebStorage.getUsageForOrigin. Get the usage of APIs 2-5 in aggregate for given
127     * origin.
128     */
129    public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
130        int callbackId = getNextId();
131        assert !mPendingGetUsageForOriginCallbacks.containsKey(callbackId);
132        mPendingGetUsageForOriginCallbacks.put(callbackId, callback);
133        nativeGetUsageAndQuotaForOrigin(mNativeAwQuotaManagerBridgeImpl, origin, callbackId, false);
134    }
135
136    @CalledByNative
137    private void onGetOriginsCallback(int callbackId, String[] origin, long[] usages,
138            long[] quotas) {
139        assert mPendingGetOriginCallbacks.containsKey(callbackId);
140        mPendingGetOriginCallbacks.remove(callbackId).onReceiveValue(
141            new Origins(origin, usages, quotas));
142    }
143
144    @CalledByNative
145    private void onGetUsageAndQuotaForOriginCallback(
146            int callbackId, boolean isQuota, long usage, long quota) {
147        if (isQuota) {
148            assert mPendingGetQuotaForOriginCallbacks.containsKey(callbackId);
149            mPendingGetQuotaForOriginCallbacks.remove(callbackId).onReceiveValue(quota);
150        } else {
151            assert mPendingGetUsageForOriginCallbacks.containsKey(callbackId);
152            mPendingGetUsageForOriginCallbacks.remove(callbackId).onReceiveValue(usage);
153        }
154    }
155
156    private native void nativeInit(long nativeAwQuotaManagerBridgeImpl);
157    private native void nativeDeleteAllData(long nativeAwQuotaManagerBridgeImpl);
158    private native void nativeDeleteOrigin(long nativeAwQuotaManagerBridgeImpl, String origin);
159    private native void nativeGetOrigins(long nativeAwQuotaManagerBridgeImpl, int callbackId);
160    private native void nativeGetUsageAndQuotaForOrigin(long nativeAwQuotaManagerBridgeImpl,
161            String origin, int callbackId, boolean isQuota);
162}
163