| 1 | // Copyright (c) 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 | |
| 5 | package org.chromium.android_webview; |
| 6 | |
| 7 | import org.chromium.base.CalledByNative; |
| 8 | import org.chromium.base.JNINamespace; |
| 9 | import org.chromium.base.ThreadUtils; |
| 10 | |
| 11 | import android.webkit.ValueCallback; |
| 12 | |
| 13 | import java.util.Map; |
| 14 | import java.util.HashMap; |
| 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") |
| 23 | public class AwQuotaManagerBridge { |
| 24 | // TODO(boliu): This should be obtained from Java AwBrowserContext that owns this. |
| 25 | private static native int 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 int 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(int 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(int nativeAwQuotaManagerBridgeImpl); |
| 157 | private native void nativeDeleteAllData(int nativeAwQuotaManagerBridgeImpl); |
| 158 | private native void nativeDeleteOrigin(int nativeAwQuotaManagerBridgeImpl, String origin); |
| 159 | private native void nativeGetOrigins(int nativeAwQuotaManagerBridgeImpl, int callbackId); |
| 160 | private native void nativeGetUsageAndQuotaForOrigin(int nativeAwQuotaManagerBridgeImpl, |
| 161 | String origin, int callbackId, boolean isQuota); |
| 162 | } |