17df1985e86635af006be3dfa65987d60e290b5deBen Murdoch/*
27df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * Copyright (C) 2009 The Android Open Source Project
37df1985e86635af006be3dfa65987d60e290b5deBen Murdoch *
47df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * Licensed under the Apache License, Version 2.0 (the "License");
57df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * you may not use this file except in compliance with the License.
67df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * You may obtain a copy of the License at
77df1985e86635af006be3dfa65987d60e290b5deBen Murdoch *
87df1985e86635af006be3dfa65987d60e290b5deBen Murdoch *      http://www.apache.org/licenses/LICENSE-2.0
97df1985e86635af006be3dfa65987d60e290b5deBen Murdoch *
107df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * Unless required by applicable law or agreed to in writing, software
117df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * distributed under the License is distributed on an "AS IS" BASIS,
127df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * See the License for the specific language governing permissions and
147df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * limitations under the License.
157df1985e86635af006be3dfa65987d60e290b5deBen Murdoch */
167df1985e86635af006be3dfa65987d60e290b5deBen Murdoch
177df1985e86635af006be3dfa65987d60e290b5deBen Murdochpackage android.webkit;
187df1985e86635af006be3dfa65987d60e290b5deBen Murdoch
1911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roardimport android.os.Handler;
2011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roardimport android.os.Message;
2111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roardimport android.util.Log;
2211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
236c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roardimport java.util.Collection;
246c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roardimport java.util.Map;
2511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roardimport java.util.HashMap;
26af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescuimport java.util.HashSet;
27af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescuimport java.util.Iterator;
28af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescuimport java.util.Set;
2911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
307df1985e86635af006be3dfa65987d60e290b5deBen Murdoch/**
317df1985e86635af006be3dfa65987d60e290b5deBen Murdoch * Functionality for manipulating the webstorage databases.
327df1985e86635af006be3dfa65987d60e290b5deBen Murdoch */
337df1985e86635af006be3dfa65987d60e290b5deBen Murdochpublic final class WebStorage {
347df1985e86635af006be3dfa65987d60e290b5deBen Murdoch
357df1985e86635af006be3dfa65987d60e290b5deBen Murdoch    /**
367df1985e86635af006be3dfa65987d60e290b5deBen Murdoch     * Encapsulates a callback function to be executed when a new quota is made
377df1985e86635af006be3dfa65987d60e290b5deBen Murdoch     * available. We primarily want this to allow us to call back the sleeping
387df1985e86635af006be3dfa65987d60e290b5deBen Murdoch     * WebCore thread from outside the WebViewCore class (as the native call
397df1985e86635af006be3dfa65987d60e290b5deBen Murdoch     * is private). It is imperative that this the setDatabaseQuota method is
407df1985e86635af006be3dfa65987d60e290b5deBen Murdoch     * executed once a decision to either allow or deny new quota is made,
417df1985e86635af006be3dfa65987d60e290b5deBen Murdoch     * otherwise the WebCore thread will remain asleep.
427df1985e86635af006be3dfa65987d60e290b5deBen Murdoch     */
437df1985e86635af006be3dfa65987d60e290b5deBen Murdoch    public interface QuotaUpdater {
447df1985e86635af006be3dfa65987d60e290b5deBen Murdoch        public void updateQuota(long newQuota);
457df1985e86635af006be3dfa65987d60e290b5deBen Murdoch    };
4611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
4711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    // Log tag
4811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private static final String TAG = "webstorage";
4911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
5011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    // Global instance of a WebStorage
5111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private static WebStorage sWebStorage;
5211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
5311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    // Message ids
5411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    static final int UPDATE = 0;
5511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    static final int SET_QUOTA_ORIGIN = 1;
5611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    static final int DELETE_ORIGIN = 2;
5711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    static final int DELETE_ALL = 3;
586c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    static final int GET_ORIGINS = 4;
596c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    static final int GET_USAGE_ORIGIN = 5;
606c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    static final int GET_QUOTA_ORIGIN = 6;
616c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
626c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    // Message ids on the UI thread
636c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    static final int RETURN_ORIGINS = 0;
646c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    static final int RETURN_USAGE_ORIGIN = 1;
656c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    static final int RETURN_QUOTA_ORIGIN = 2;
666c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
676c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private static final String ORIGINS = "origins";
686c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private static final String ORIGIN = "origin";
696c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private static final String CALLBACK = "callback";
706c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private static final String USAGE = "usage";
716c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private static final String QUOTA = "quota";
7211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
736c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private Map <String, Origin> mOrigins;
7411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
7511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private Handler mHandler = null;
766c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private Handler mUIHandler = null;
7711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
789b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck    /**
799b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck     * Class containing the HTML5 database quota and usage for an origin.
809b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck     */
8187745ce21fe3f65b8cf7a92372c24227821318d3John Reck    public static class Origin {
8287745ce21fe3f65b8cf7a92372c24227821318d3John Reck        private String mOrigin = null;
8387745ce21fe3f65b8cf7a92372c24227821318d3John Reck        private long mQuota = 0;
8487745ce21fe3f65b8cf7a92372c24227821318d3John Reck        private long mUsage = 0;
856c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
8687745ce21fe3f65b8cf7a92372c24227821318d3John Reck        private Origin(String origin, long quota, long usage) {
876c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            mOrigin = origin;
886c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            mQuota = quota;
896c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            mUsage = usage;
906c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        }
9111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
9287745ce21fe3f65b8cf7a92372c24227821318d3John Reck        private Origin(String origin, long quota) {
9311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            mOrigin = origin;
9411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            mQuota = quota;
9511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
9611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
9787745ce21fe3f65b8cf7a92372c24227821318d3John Reck        private Origin(String origin) {
9811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            mOrigin = origin;
9911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
10011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
1019b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck        /**
1029b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * An origin string is created using WebCore::SecurityOrigin::toString().
1039b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * Note that WebCore::SecurityOrigin uses 0 (which is not printed) for
1049b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * the port if the port is the default for the protocol. Eg
1059b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * http://www.google.com and http://www.google.com:80 both record a port
1069b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * of 0 and hence toString() == 'http://www.google.com' for both.
1079b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * @return The origin string.
1089b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         */
10911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        public String getOrigin() {
11011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            return mOrigin;
11111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
11211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
1139b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck        /**
1149b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * Returns the quota for this origin's HTML5 database.
1159b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * @return The quota in bytes.
1169b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         */
11711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        public long getQuota() {
11811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            return mQuota;
11911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
1206c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
1219b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck        /**
1229b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * Returns the usage for this origin's HTML5 database.
1239b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         * @return The usage in bytes.
1249b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck         */
1256c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        public long getUsage() {
1266c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            return mUsage;
1276c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        }
1286c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    }
1296c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
1306c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    /**
1316c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * @hide
1326c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * Message handler, UI side
1336c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     */
1346c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    public void createUIHandler() {
1356c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (mUIHandler == null) {
1366c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            mUIHandler = new Handler() {
1376c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                @Override
1386c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                public void handleMessage(Message msg) {
1396c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                    switch (msg.what) {
1406c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                        case RETURN_ORIGINS: {
1416c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map values = (Map) msg.obj;
1426c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map origins = (Map) values.get(ORIGINS);
1436c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            ValueCallback<Map> callback = (ValueCallback<Map>) values.get(CALLBACK);
1446c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            callback.onReceiveValue(origins);
1456c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            } break;
1466c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
1476c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                        case RETURN_USAGE_ORIGIN: {
1486c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map values = (Map) msg.obj;
1496c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
1506c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            callback.onReceiveValue((Long)values.get(USAGE));
1516c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            } break;
1526c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
1536c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                        case RETURN_QUOTA_ORIGIN: {
1546c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map values = (Map) msg.obj;
1556c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
1566c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            callback.onReceiveValue((Long)values.get(QUOTA));
1576c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            } break;
1586c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                    }
1596c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                }
1606c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            };
1616c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        }
16211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
16311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
16411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
16511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * @hide
1666c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * Message handler, webcore side
16711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
168e4b2d4dc7db426052d1dfebc40f6b64a001b6d73Steve Block    public synchronized void createHandler() {
16911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        if (mHandler == null) {
17011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            mHandler = new Handler() {
17111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                @Override
17211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                public void handleMessage(Message msg) {
17311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                    switch (msg.what) {
17411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                        case SET_QUOTA_ORIGIN: {
17511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            Origin website = (Origin) msg.obj;
17611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            nativeSetQuotaForOrigin(website.getOrigin(),
17711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                                                    website.getQuota());
17811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            } break;
17911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
18011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                        case DELETE_ORIGIN: {
18111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            Origin website = (Origin) msg.obj;
18211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            nativeDeleteOrigin(website.getOrigin());
18311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            } break;
18411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
18511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                        case DELETE_ALL:
186af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescu                            nativeDeleteAllData();
18711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            break;
18811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
1896c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                        case GET_ORIGINS: {
1906c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            syncValues();
1916c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            ValueCallback callback = (ValueCallback) msg.obj;
1926c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map origins = new HashMap(mOrigins);
1936c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map values = new HashMap<String, Object>();
1946c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            values.put(CALLBACK, callback);
1956c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            values.put(ORIGINS, origins);
1966c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
1976c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            } break;
1986c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
1996c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                        case GET_USAGE_ORIGIN: {
2006c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            syncValues();
2016c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map values = (Map) msg.obj;
2026c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            String origin = (String) values.get(ORIGIN);
2036c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            ValueCallback callback = (ValueCallback) values.get(CALLBACK);
2046c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Origin website = mOrigins.get(origin);
2056c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map retValues = new HashMap<String, Object>();
2066c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            retValues.put(CALLBACK, callback);
2076c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            if (website != null) {
2086c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                                long usage = website.getUsage();
2096c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                                retValues.put(USAGE, new Long(usage));
2106c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            }
2116c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            postUIMessage(Message.obtain(null, RETURN_USAGE_ORIGIN, retValues));
2126c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            } break;
2136c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
2146c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                        case GET_QUOTA_ORIGIN: {
2156c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            syncValues();
2166c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map values = (Map) msg.obj;
2176c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            String origin = (String) values.get(ORIGIN);
2186c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            ValueCallback callback = (ValueCallback) values.get(CALLBACK);
2196c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Origin website = mOrigins.get(origin);
2206c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            Map retValues = new HashMap<String, Object>();
2216c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            retValues.put(CALLBACK, callback);
2226c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            if (website != null) {
2236c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                                long quota = website.getQuota();
2246c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                                retValues.put(QUOTA, new Long(quota));
2256c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            }
2266c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            postUIMessage(Message.obtain(null, RETURN_QUOTA_ORIGIN, retValues));
2276c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                            } break;
2286c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
22911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                        case UPDATE:
23011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            syncValues();
23111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                            break;
23211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                    }
23311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard                }
23411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            };
23511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
23611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
23711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
2386c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    /*
2396c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * When calling getOrigins(), getUsageForOrigin() and getQuotaForOrigin(),
2406c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * we need to get the values from webcore, but we cannot block while doing so
2416c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * as we used to do, as this could result in a full deadlock (other webcore
2426c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * messages received while we are still blocked here, see http://b/2127737).
2436c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     *
2446c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * We have to do everything asynchronously, by providing a callback function.
2456c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * We post a message on the webcore thread (mHandler) that will get the result
2466c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * from webcore, and we post it back on the UI thread (using mUIHandler).
2476c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * We can then use the callback function to return the value.
2486c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     */
2496c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
25011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
2519b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck     * Returns a list of origins having a database. The Map is of type
2529b2a59bdd27cfa45c7bb3b58eb705b35589b7050John Reck     * Map<String, Origin>.
25311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
2546c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    public void getOrigins(ValueCallback<Map> callback) {
2556c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (callback != null) {
2566c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
2576c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                syncValues();
2586c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                callback.onReceiveValue(mOrigins);
2596c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            } else {
2606c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard                postMessage(Message.obtain(null, GET_ORIGINS, callback));
26159e2ad93bf37c7ded44c033d38fe7c972e2f4118Andrei Popescu            }
26211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
2636c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    }
2646c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
2656c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    /**
2666c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * Returns a list of origins having a database
2676c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * should only be called from WebViewCore.
2686c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     */
2696c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    Collection<Origin> getOriginsSync() {
2706c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
2716c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            update();
2726c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            return mOrigins.values();
2736c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        }
2746c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        return null;
27511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
27611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
27711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
27811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Returns the use for a given origin
27911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
2806c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
2816c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (callback == null) {
2826c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            return;
2836c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        }
28411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        if (origin == null) {
2856c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            callback.onReceiveValue(null);
2866c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            return;
28711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
2886c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
2896c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            syncValues();
2906c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            Origin website = mOrigins.get(origin);
2916c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            callback.onReceiveValue(new Long(website.getUsage()));
2926c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        } else {
2936c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            HashMap values = new HashMap<String, Object>();
2946c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            values.put(ORIGIN, origin);
2956c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            values.put(CALLBACK, callback);
2966c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            postMessage(Message.obtain(null, GET_USAGE_ORIGIN, values));
29711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
29811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
29911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
30011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
30111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Returns the quota for a given origin
30211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
3036c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
3046c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (callback == null) {
3056c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            return;
3066c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        }
30711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        if (origin == null) {
3086c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            callback.onReceiveValue(null);
3096c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            return;
31011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
3116c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
3126c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            syncValues();
3136c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            Origin website = mOrigins.get(origin);
3146c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            callback.onReceiveValue(new Long(website.getUsage()));
3156c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        } else {
3166c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            HashMap values = new HashMap<String, Object>();
3176c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            values.put(ORIGIN, origin);
3186c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            values.put(CALLBACK, callback);
3196c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            postMessage(Message.obtain(null, GET_QUOTA_ORIGIN, values));
32011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
32111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
32211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
32311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
32411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Set the quota for a given origin
32511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
32611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    public void setQuotaForOrigin(String origin, long quota) {
32711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        if (origin != null) {
3285647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
3295647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch                nativeSetQuotaForOrigin(origin, quota);
3305647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            } else {
3315647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch                postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
3325647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch                    new Origin(origin, quota)));
3335647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            }
33411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
33511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
33611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
33711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
33811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Delete a given origin
33911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
34011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    public void deleteOrigin(String origin) {
34111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        if (origin != null) {
3425647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
3435647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch                nativeDeleteOrigin(origin);
3445647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            } else {
3455647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch                postMessage(Message.obtain(null, DELETE_ORIGIN,
3465647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch                    new Origin(origin)));
3475647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            }
34811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
34911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
35011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
35111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
35211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Delete all databases
35311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
354af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescu    public void deleteAllData() {
3555647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
356af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescu            nativeDeleteAllData();
3575647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch        } else {
3585647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            postMessage(Message.obtain(null, DELETE_ALL));
3595647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch        }
36011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
36111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
36211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
363427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block     * Sets the maximum size of the ApplicationCache.
364427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block     * This should only ever be called on the WebKit thread.
365427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block     * @hide Pending API council approval
366427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block     */
367427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block    public void setAppCacheMaximumSize(long size) {
368427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block        nativeSetAppCacheMaximumSize(size);
369427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block    }
370427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block
371427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block    /**
37211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Utility function to send a message to our handler
37311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
374e4b2d4dc7db426052d1dfebc40f6b64a001b6d73Steve Block    private synchronized void postMessage(Message msg) {
37511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        if (mHandler != null) {
37611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard            mHandler.sendMessage(msg);
37711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
37811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
37911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
38011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
3816c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     * Utility function to send a message to the handler on the UI thread
3826c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard     */
3836c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    private void postUIMessage(Message msg) {
3846c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        if (mUIHandler != null) {
3856c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            mUIHandler.sendMessage(msg);
3866c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        }
3876c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    }
3886c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard
3896c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard    /**
39011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Get the global instance of WebStorage.
39111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * @return A single instance of WebStorage.
39211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
39311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    public static WebStorage getInstance() {
39411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard      if (sWebStorage == null) {
39511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard          sWebStorage = new WebStorage();
39611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard      }
39711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard      return sWebStorage;
39811e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
39911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
40011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
40111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * @hide
40211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Post a Sync request
40311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
40411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    public void update() {
4055647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
4065647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            syncValues();
4075647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch        } else {
4085647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch            postMessage(Message.obtain(null, UPDATE));
4095647bb3cc21428dd5242255323dff13c71a3343dBen Murdoch        }
41011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
41111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
41211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    /**
41311e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     * Run on the webcore thread
4149a56bb838c099a318d4f961f290d324ed5f1949dAndrei Popescu     * set the local values with the current ones
41511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard     */
41611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private void syncValues() {
4176c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        Set<String> tmp = nativeGetOrigins();
4186c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        mOrigins = new HashMap<String, Origin>();
4196c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard        for (String origin : tmp) {
4206c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            Origin website = new Origin(origin,
42198409704134c262fdaab47055f60b7e01a4bc0b2Andrei Popescu                                 nativeGetQuotaForOrigin(origin),
42298409704134c262fdaab47055f60b7e01a4bc0b2Andrei Popescu                                 nativeGetUsageForOrigin(origin));
4236c24b4d10223cb522e6bdbf0e334f61e672f4366Nicolas Roard            mOrigins.put(origin, website);
42411e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard        }
42511e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    }
42611e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard
42711e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    // Native functions
428af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescu    private static native Set nativeGetOrigins();
42911e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private static native long nativeGetUsageForOrigin(String origin);
43011e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private static native long nativeGetQuotaForOrigin(String origin);
43111e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private static native void nativeSetQuotaForOrigin(String origin, long quota);
43211e8fe5a7208c9cd6afc2a0373761ae506d7707fNicolas Roard    private static native void nativeDeleteOrigin(String origin);
433af9c77edbddfcf87a4dc17b95db84bf741674a9aAndrei Popescu    private static native void nativeDeleteAllData();
434427efcca1988e3f424e363808e8fd0978f4e78d1Steve Block    private static native void nativeSetAppCacheMaximumSize(long size);
4357df1985e86635af006be3dfa65987d60e290b5deBen Murdoch}
436