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