blob: f27360d0032f14965498e0636ba15c0ba1631283 [file] [log] [blame]
Ben Murdoch7df19852009-04-22 13:07:58 +01001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
Nicolas Roard11e8fe52009-05-11 15:04:16 +010019import android.os.Handler;
20import android.os.Message;
21import android.util.Log;
22
23import java.util.concurrent.locks.Condition;
24import java.util.concurrent.locks.Lock;
25import java.util.concurrent.locks.ReentrantLock;
26import java.util.HashMap;
27import java.util.Vector;
28
Ben Murdoch7df19852009-04-22 13:07:58 +010029/**
30 * Functionality for manipulating the webstorage databases.
31 */
32public final class WebStorage {
33
34 /**
35 * Encapsulates a callback function to be executed when a new quota is made
36 * available. We primarily want this to allow us to call back the sleeping
37 * WebCore thread from outside the WebViewCore class (as the native call
38 * is private). It is imperative that this the setDatabaseQuota method is
39 * executed once a decision to either allow or deny new quota is made,
40 * otherwise the WebCore thread will remain asleep.
41 */
42 public interface QuotaUpdater {
43 public void updateQuota(long newQuota);
44 };
Nicolas Roard11e8fe52009-05-11 15:04:16 +010045
46 // Log tag
47 private static final String TAG = "webstorage";
48
49 // Global instance of a WebStorage
50 private static WebStorage sWebStorage;
51
52 // We keep a copy of the origins, quotas and usages
53 // that we protect via a lock and update in syncValues()
54 private static Lock mLock = new ReentrantLock();
55 private static Condition mCacheUpdated = mLock.newCondition();
56
57 // Message ids
58 static final int UPDATE = 0;
59 static final int SET_QUOTA_ORIGIN = 1;
60 static final int DELETE_ORIGIN = 2;
61 static final int DELETE_ALL = 3;
62
63 private Vector <String> mOrigins;
64 private HashMap <String, Long> mQuotas = new HashMap<String, Long>();
65 private HashMap <String, Long> mUsages = new HashMap<String, Long>();
66
67 private Handler mHandler = null;
68
69 private class Origin {
70 String mOrigin = null;
71 long mQuota = 0;
72
73 public Origin(String origin, long quota) {
74 mOrigin = origin;
75 mQuota = quota;
76 }
77
78 public Origin(String origin) {
79 mOrigin = origin;
80 }
81
82 public String getOrigin() {
83 return mOrigin;
84 }
85
86 public long getQuota() {
87 return mQuota;
88 }
89 }
90
91 /**
92 * @hide
93 * Message handler
94 */
95 public void createHandler() {
96 if (mHandler == null) {
97 mHandler = new Handler() {
98 @Override
99 public void handleMessage(Message msg) {
100 switch (msg.what) {
101 case SET_QUOTA_ORIGIN: {
102 Origin website = (Origin) msg.obj;
103 nativeSetQuotaForOrigin(website.getOrigin(),
104 website.getQuota());
105 syncValues();
106 } break;
107
108 case DELETE_ORIGIN: {
109 Origin website = (Origin) msg.obj;
110 nativeDeleteOrigin(website.getOrigin());
111 syncValues();
112 } break;
113
114 case DELETE_ALL:
115 nativeDeleteAllDatabases();
116 syncValues();
117 break;
118
119 case UPDATE:
120 syncValues();
121 break;
122 }
123 }
124 };
125 }
126 }
127
128 /**
129 * @hide
130 * Returns a list of origins having a database
131 */
132 public Vector getOrigins() {
133 Vector ret = null;
134 mLock.lock();
135 try {
136 update();
137 mCacheUpdated.await();
138 ret = mOrigins;
139 } catch (InterruptedException e) {
140 Log.e(TAG, "Exception while waiting on the updated origins", e);
141 } finally {
142 mLock.unlock();
143 }
144 return ret;
145 }
146
147 /**
148 * @hide
149 * Returns the use for a given origin
150 */
151 public long getUsageForOrigin(String origin) {
152 long ret = 0;
153 if (origin == null) {
154 return ret;
155 }
156 mLock.lock();
157 try {
158 update();
159 mCacheUpdated.await();
160 Long usage = mUsages.get(origin);
161 if (usage != null) {
162 ret = usage.longValue();
163 }
164 } catch (InterruptedException e) {
165 Log.e(TAG, "Exception while waiting on the updated origins", e);
166 } finally {
167 mLock.unlock();
168 }
169 return ret;
170 }
171
172 /**
173 * @hide
174 * Returns the quota for a given origin
175 */
176 public long getQuotaForOrigin(String origin) {
177 long ret = 0;
178 if (origin == null) {
179 return ret;
180 }
181 mLock.lock();
182 try {
183 update();
184 mCacheUpdated.await();
185 Long quota = mQuotas.get(origin);
186 if (quota != null) {
187 ret = quota.longValue();
188 }
189 } catch (InterruptedException e) {
190 Log.e(TAG, "Exception while waiting on the updated origins", e);
191 } finally {
192 mLock.unlock();
193 }
194 return ret;
195 }
196
197 /**
198 * @hide
199 * Set the quota for a given origin
200 */
201 public void setQuotaForOrigin(String origin, long quota) {
202 if (origin != null) {
203 postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
204 new Origin(origin, quota)));
205 }
206 }
207
208 /**
209 * @hide
210 * Delete a given origin
211 */
212 public void deleteOrigin(String origin) {
213 if (origin != null) {
214 postMessage(Message.obtain(null, DELETE_ORIGIN,
215 new Origin(origin)));
216 }
217 }
218
219 /**
220 * @hide
221 * Delete all databases
222 */
223 public void deleteAllDatabases() {
224 postMessage(Message.obtain(null, DELETE_ALL));
225 }
226
227 /**
228 * Utility function to send a message to our handler
229 */
230 private void postMessage(Message msg) {
231 if (mHandler != null) {
232 mHandler.sendMessage(msg);
233 }
234 }
235
236 /**
237 * @hide
238 * Get the global instance of WebStorage.
239 * @return A single instance of WebStorage.
240 */
241 public static WebStorage getInstance() {
242 if (sWebStorage == null) {
243 sWebStorage = new WebStorage();
244 }
245 return sWebStorage;
246 }
247
248 /**
249 * @hide
250 * Post a Sync request
251 */
252 public void update() {
253 postMessage(Message.obtain(null, UPDATE));
254 }
255
256 /**
257 * Run on the webcore thread
258 * sync the local cached values with the real ones
259 */
260 private void syncValues() {
261 mLock.lock();
262 Vector tmp = nativeGetOrigins();
263 mOrigins = new Vector<String>();
264 mQuotas.clear();
265 mUsages.clear();
266 for (int i = 0; i < tmp.size(); i++) {
267 String origin = (String) tmp.get(i);
268 mOrigins.add(origin);
269 mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
270 mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
271 }
272 mCacheUpdated.signal();
273 mLock.unlock();
274 }
275
276 // Native functions
277 private static native Vector nativeGetOrigins();
278 private static native long nativeGetUsageForOrigin(String origin);
279 private static native long nativeGetQuotaForOrigin(String origin);
280 private static native void nativeSetQuotaForOrigin(String origin, long quota);
281 private static native void nativeDeleteOrigin(String origin);
282 private static native void nativeDeleteAllDatabases();
Ben Murdoch7df19852009-04-22 13:07:58 +0100283}