diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/webkit/WebViewDatabase.java | |
parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
download | frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/webkit/WebViewDatabase.java')
-rw-r--r-- | core/java/android/webkit/WebViewDatabase.java | 967 |
1 files changed, 967 insertions, 0 deletions
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java new file mode 100644 index 0000000..1004e30 --- /dev/null +++ b/core/java/android/webkit/WebViewDatabase.java @@ -0,0 +1,967 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.webkit; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import java.util.Map.Entry; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; +import android.util.Log; +import android.webkit.CookieManager.Cookie; +import android.webkit.CacheManager.CacheResult; + +public class WebViewDatabase { + private static final String DATABASE_FILE = "webview.db"; + private static final String CACHE_DATABASE_FILE = "webviewCache.db"; + + // log tag + protected static final String LOGTAG = "webviewdatabase"; + + private static final int DATABASE_VERSION = 9; + // 2 -> 3 Modified Cache table to allow cache of redirects + // 3 -> 4 Added Oma-Downloads table + // 4 -> 5 Modified Cache table to support persistent contentLength + // 5 -> 4 Removed Oma-Downoads table + // 5 -> 6 Add INDEX for cache table + // 6 -> 7 Change cache localPath from int to String + // 7 -> 8 Move cache to its own db + // 8 -> 9 Store both scheme and host when storing passwords + private static final int CACHE_DATABASE_VERSION = 1; + + private static WebViewDatabase mInstance = null; + + private static SQLiteDatabase mDatabase = null; + private static SQLiteDatabase mCacheDatabase = null; + + // synchronize locks + private final Object mCookieLock = new Object(); + private final Object mPasswordLock = new Object(); + private final Object mFormLock = new Object(); + private final Object mHttpAuthLock = new Object(); + + private static final String mTableNames[] = { + "cookies", "password", "formurl", "formdata", "httpauth" + }; + + // Table ids (they are index to mTableNames) + private static final int TABLE_COOKIES_ID = 0; + + private static final int TABLE_PASSWORD_ID = 1; + + private static final int TABLE_FORMURL_ID = 2; + + private static final int TABLE_FORMDATA_ID = 3; + + private static final int TABLE_HTTPAUTH_ID = 4; + + // column id strings for "_id" which can be used by any table + private static final String ID_COL = "_id"; + + private static final String[] ID_PROJECTION = new String[] { + "_id" + }; + + // column id strings for "cookies" table + private static final String COOKIES_NAME_COL = "name"; + + private static final String COOKIES_VALUE_COL = "value"; + + private static final String COOKIES_DOMAIN_COL = "domain"; + + private static final String COOKIES_PATH_COL = "path"; + + private static final String COOKIES_EXPIRES_COL = "expires"; + + private static final String COOKIES_SECURE_COL = "secure"; + + // column id strings for "cache" table + private static final String CACHE_URL_COL = "url"; + + private static final String CACHE_FILE_PATH_COL = "filepath"; + + private static final String CACHE_LAST_MODIFY_COL = "lastmodify"; + + private static final String CACHE_ETAG_COL = "etag"; + + private static final String CACHE_EXPIRES_COL = "expires"; + + private static final String CACHE_MIMETYPE_COL = "mimetype"; + + private static final String CACHE_ENCODING_COL = "encoding"; + + private static final String CACHE_HTTP_STATUS_COL = "httpstatus"; + + private static final String CACHE_LOCATION_COL = "location"; + + private static final String CACHE_CONTENTLENGTH_COL = "contentlength"; + + // column id strings for "password" table + private static final String PASSWORD_HOST_COL = "host"; + + private static final String PASSWORD_USERNAME_COL = "username"; + + private static final String PASSWORD_PASSWORD_COL = "password"; + + // column id strings for "formurl" table + private static final String FORMURL_URL_COL = "url"; + + // column id strings for "formdata" table + private static final String FORMDATA_URLID_COL = "urlid"; + + private static final String FORMDATA_NAME_COL = "name"; + + private static final String FORMDATA_VALUE_COL = "value"; + + // column id strings for "httpauth" table + private static final String HTTPAUTH_HOST_COL = "host"; + + private static final String HTTPAUTH_REALM_COL = "realm"; + + private static final String HTTPAUTH_USERNAME_COL = "username"; + + private static final String HTTPAUTH_PASSWORD_COL = "password"; + + // use InsertHelper to improve insert performance by 40% + private static DatabaseUtils.InsertHelper mCacheInserter; + private static int mCacheUrlColIndex; + private static int mCacheFilePathColIndex; + private static int mCacheLastModifyColIndex; + private static int mCacheETagColIndex; + private static int mCacheExpiresColIndex; + private static int mCacheMimeTypeColIndex; + private static int mCacheEncodingColIndex; + private static int mCacheHttpStatusColIndex; + private static int mCacheLocationColIndex; + private static int mCacheContentLengthColIndex; + + private static int mCacheTransactionRefcount; + + private WebViewDatabase() { + // Singleton only, use getInstance() + } + + public static synchronized WebViewDatabase getInstance(Context context) { + if (mInstance == null) { + mInstance = new WebViewDatabase(); + mDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0, null); + + // mDatabase should not be null, + // the only case is RequestAPI test has problem to create db + if (mDatabase != null && mDatabase.getVersion() != DATABASE_VERSION) { + mDatabase.beginTransaction(); + try { + upgradeDatabase(); + mDatabase.setTransactionSuccessful(); + } finally { + mDatabase.endTransaction(); + } + } + + if (mDatabase != null) { + // use per table Mutex lock, turn off database lock, this + // improves performance as database's ReentrantLock is expansive + mDatabase.setLockingEnabled(false); + } + + mCacheDatabase = context.openOrCreateDatabase(CACHE_DATABASE_FILE, + 0, null); + + // mCacheDatabase should not be null, + // the only case is RequestAPI test has problem to create db + if (mCacheDatabase != null + && mCacheDatabase.getVersion() != CACHE_DATABASE_VERSION) { + mCacheDatabase.beginTransaction(); + try { + upgradeCacheDatabase(); + bootstrapCacheDatabase(); + mCacheDatabase.setTransactionSuccessful(); + } finally { + mCacheDatabase.endTransaction(); + } + // Erase the files from the file system in the + // case that the database was updated and the + // there were existing cache content + CacheManager.removeAllCacheFiles(); + } + + if (mCacheDatabase != null) { + // use InsertHelper for faster insertion + mCacheInserter = new DatabaseUtils.InsertHelper(mCacheDatabase, + "cache"); + mCacheUrlColIndex = mCacheInserter + .getColumnIndex(CACHE_URL_COL); + mCacheFilePathColIndex = mCacheInserter + .getColumnIndex(CACHE_FILE_PATH_COL); + mCacheLastModifyColIndex = mCacheInserter + .getColumnIndex(CACHE_LAST_MODIFY_COL); + mCacheETagColIndex = mCacheInserter + .getColumnIndex(CACHE_ETAG_COL); + mCacheExpiresColIndex = mCacheInserter + .getColumnIndex(CACHE_EXPIRES_COL); + mCacheMimeTypeColIndex = mCacheInserter + .getColumnIndex(CACHE_MIMETYPE_COL); + mCacheEncodingColIndex = mCacheInserter + .getColumnIndex(CACHE_ENCODING_COL); + mCacheHttpStatusColIndex = mCacheInserter + .getColumnIndex(CACHE_HTTP_STATUS_COL); + mCacheLocationColIndex = mCacheInserter + .getColumnIndex(CACHE_LOCATION_COL); + mCacheContentLengthColIndex = mCacheInserter + .getColumnIndex(CACHE_CONTENTLENGTH_COL); + } + } + + return mInstance; + } + + private static void upgradeDatabase() { + int oldVersion = mDatabase.getVersion(); + if (oldVersion != 0) { + Log.i(LOGTAG, "Upgrading database from version " + + oldVersion + " to " + + DATABASE_VERSION + ", which will destroy old data"); + } + boolean justPasswords = 8 == oldVersion && 9 == DATABASE_VERSION; + if (!justPasswords) { + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_COOKIES_ID]); + mDatabase.execSQL("DROP TABLE IF EXISTS cache"); + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_FORMURL_ID]); + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_FORMDATA_ID]); + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_HTTPAUTH_ID]); + } + mDatabase.execSQL("DROP TABLE IF EXISTS " + + mTableNames[TABLE_PASSWORD_ID]); + + mDatabase.setVersion(DATABASE_VERSION); + + if (!justPasswords) { + // cookies + mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_COOKIES_ID] + + " (" + ID_COL + " INTEGER PRIMARY KEY, " + + COOKIES_NAME_COL + " TEXT, " + COOKIES_VALUE_COL + + " TEXT, " + COOKIES_DOMAIN_COL + " TEXT, " + + COOKIES_PATH_COL + " TEXT, " + COOKIES_EXPIRES_COL + + " INTEGER, " + COOKIES_SECURE_COL + " INTEGER" + ");"); + mDatabase.execSQL("CREATE INDEX cookiesIndex ON " + + mTableNames[TABLE_COOKIES_ID] + " (path)"); + + // formurl + mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMURL_ID] + + " (" + ID_COL + " INTEGER PRIMARY KEY, " + FORMURL_URL_COL + + " TEXT" + ");"); + + // formdata + mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMDATA_ID] + + " (" + ID_COL + " INTEGER PRIMARY KEY, " + + FORMDATA_URLID_COL + " INTEGER, " + FORMDATA_NAME_COL + + " TEXT, " + FORMDATA_VALUE_COL + " TEXT," + " UNIQUE (" + + FORMDATA_URLID_COL + ", " + FORMDATA_NAME_COL + ", " + + FORMDATA_VALUE_COL + ") ON CONFLICT IGNORE);"); + + // httpauth + mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID] + + " (" + ID_COL + " INTEGER PRIMARY KEY, " + + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL + + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, " + + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE (" + + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL + ", " + + HTTPAUTH_USERNAME_COL + ") ON CONFLICT REPLACE);"); + } + // passwords + mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID] + + " (" + ID_COL + " INTEGER PRIMARY KEY, " + + PASSWORD_HOST_COL + " TEXT, " + PASSWORD_USERNAME_COL + + " TEXT, " + PASSWORD_PASSWORD_COL + " TEXT," + " UNIQUE (" + + PASSWORD_HOST_COL + ", " + PASSWORD_USERNAME_COL + + ") ON CONFLICT REPLACE);"); + } + + private static void upgradeCacheDatabase() { + int oldVersion = mCacheDatabase.getVersion(); + if (oldVersion != 0) { + Log.i(LOGTAG, "Upgrading cache database from version " + + oldVersion + " to " + + DATABASE_VERSION + ", which will destroy all old data"); + } + mCacheDatabase.execSQL("DROP TABLE IF EXISTS cache"); + mCacheDatabase.setVersion(CACHE_DATABASE_VERSION); + } + + private static void bootstrapCacheDatabase() { + if (mCacheDatabase != null) { + mCacheDatabase.execSQL("CREATE TABLE cache" + + " (" + ID_COL + " INTEGER PRIMARY KEY, " + CACHE_URL_COL + + " TEXT, " + CACHE_FILE_PATH_COL + " TEXT, " + + CACHE_LAST_MODIFY_COL + " TEXT, " + CACHE_ETAG_COL + + " TEXT, " + CACHE_EXPIRES_COL + " INTEGER, " + + CACHE_MIMETYPE_COL + " TEXT, " + CACHE_ENCODING_COL + + " TEXT," + CACHE_HTTP_STATUS_COL + " INTEGER, " + + CACHE_LOCATION_COL + " TEXT, " + CACHE_CONTENTLENGTH_COL + + " INTEGER, " + " UNIQUE (" + CACHE_URL_COL + + ") ON CONFLICT REPLACE);"); + mCacheDatabase.execSQL("CREATE INDEX cacheUrlIndex ON cache (" + + CACHE_URL_COL + ")"); + } + } + + private boolean hasEntries(int tableId) { + if (mDatabase == null) { + return false; + } + + Cursor cursor = mDatabase.query(mTableNames[tableId], ID_PROJECTION, + null, null, null, null, null); + boolean ret = cursor.moveToFirst() == true; + cursor.close(); + return ret; + } + + // + // cookies functions + // + + /** + * Get cookies in the format of CookieManager.Cookie inside an ArrayList for + * a given domain + * + * @return ArrayList<Cookie> If nothing is found, return an empty list. + */ + ArrayList<Cookie> getCookiesForDomain(String domain) { + ArrayList<Cookie> list = new ArrayList<Cookie>(); + if (domain == null || mDatabase == null) { + return list; + } + + synchronized (mCookieLock) { + final String[] columns = new String[] { + ID_COL, COOKIES_DOMAIN_COL, COOKIES_PATH_COL, + COOKIES_NAME_COL, COOKIES_VALUE_COL, COOKIES_EXPIRES_COL, + COOKIES_SECURE_COL + }; + final String selection = "(" + COOKIES_DOMAIN_COL + + " GLOB '*' || ?)"; + Cursor cursor = mDatabase.query(mTableNames[TABLE_COOKIES_ID], + columns, selection, new String[] { domain }, null, null, + null); + if (cursor.moveToFirst()) { + int domainCol = cursor.getColumnIndex(COOKIES_DOMAIN_COL); + int pathCol = cursor.getColumnIndex(COOKIES_PATH_COL); + int nameCol = cursor.getColumnIndex(COOKIES_NAME_COL); + int valueCol = cursor.getColumnIndex(COOKIES_VALUE_COL); + int expiresCol = cursor.getColumnIndex(COOKIES_EXPIRES_COL); + int secureCol = cursor.getColumnIndex(COOKIES_SECURE_COL); + do { + Cookie cookie = new Cookie(); + cookie.domain = cursor.getString(domainCol); + cookie.path = cursor.getString(pathCol); + cookie.name = cursor.getString(nameCol); + cookie.value = cursor.getString(valueCol); + if (cursor.isNull(expiresCol)) { + cookie.expires = -1; + } else { + cookie.expires = cursor.getLong(expiresCol); + } + cookie.secure = cursor.getShort(secureCol) != 0; + cookie.mode = Cookie.MODE_NORMAL; + list.add(cookie); + } while (cursor.moveToNext()); + } + cursor.close(); + return list; + } + } + + /** + * Delete cookies which matches (domain, path, name). + * + * @param domain If it is null, nothing happens. + * @param path If it is null, all the cookies match (domain) will be + * deleted. + * @param name If it is null, all the cookies match (domain, path) will be + * deleted. + */ + void deleteCookies(String domain, String path, String name) { + if (domain == null || mDatabase == null) { + return; + } + + synchronized (mCookieLock) { + final String where = "(" + COOKIES_DOMAIN_COL + " == ?) AND (" + + COOKIES_PATH_COL + " == ?) AND (" + COOKIES_NAME_COL + + " == ?)"; + mDatabase.delete(mTableNames[TABLE_COOKIES_ID], where, + new String[] { domain, path, name }); + } + } + + /** + * Add a cookie to the database + * + * @param cookie + */ + void addCookie(Cookie cookie) { + if (cookie.domain == null || cookie.path == null || cookie.name == null + || mDatabase == null) { + return; + } + + synchronized (mCookieLock) { + ContentValues cookieVal = new ContentValues(); + cookieVal.put(COOKIES_DOMAIN_COL, cookie.domain); + cookieVal.put(COOKIES_PATH_COL, cookie.path); + cookieVal.put(COOKIES_NAME_COL, cookie.name); + cookieVal.put(COOKIES_VALUE_COL, cookie.value); + if (cookie.expires != -1) { + cookieVal.put(COOKIES_EXPIRES_COL, cookie.expires); + } + cookieVal.put(COOKIES_SECURE_COL, cookie.secure); + mDatabase.insert(mTableNames[TABLE_COOKIES_ID], null, cookieVal); + } + } + + /** + * Whether there is any cookies in the database + * + * @return TRUE if there is cookie. + */ + boolean hasCookies() { + synchronized (mCookieLock) { + return hasEntries(TABLE_COOKIES_ID); + } + } + + /** + * Clear cookie database + */ + void clearCookies() { + if (mDatabase == null) { + return; + } + + synchronized (mCookieLock) { + mDatabase.delete(mTableNames[TABLE_COOKIES_ID], null, null); + } + } + + /** + * Clear session cookies, which means cookie doesn't have EXPIRES. + */ + void clearSessionCookies() { + if (mDatabase == null) { + return; + } + + final String sessionExpired = COOKIES_EXPIRES_COL + " ISNULL"; + synchronized (mCookieLock) { + mDatabase.delete(mTableNames[TABLE_COOKIES_ID], sessionExpired, + null); + } + } + + /** + * Clear expired cookies + * + * @param now Time for now + */ + void clearExpiredCookies(long now) { + if (mDatabase == null) { + return; + } + + final String expires = COOKIES_EXPIRES_COL + " <= ?"; + synchronized (mCookieLock) { + mDatabase.delete(mTableNames[TABLE_COOKIES_ID], expires, + new String[] { Long.toString(now) }); + } + } + + // + // cache functions, can only be called from WebCoreThread + // + + boolean startCacheTransaction() { + if (++mCacheTransactionRefcount == 1) { + mCacheDatabase.beginTransaction(); + return true; + } + return false; + } + + boolean endCacheTransaction() { + if (--mCacheTransactionRefcount == 0) { + try { + mCacheDatabase.setTransactionSuccessful(); + } finally { + mCacheDatabase.endTransaction(); + } + return true; + } + return false; + } + + /** + * Get a cache item. + * + * @param url The url + * @return CacheResult The CacheManager.CacheResult + */ + CacheResult getCache(String url) { + if (url == null || mCacheDatabase == null) { + return null; + } + + Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, " + + "mimetype, encoding, httpstatus, location, contentlength " + + "FROM cache WHERE url = ?", + new String[] { url }); + + try { + if (cursor.moveToFirst()) { + CacheResult ret = new CacheResult(); + ret.localPath = cursor.getString(0); + ret.lastModified = cursor.getString(1); + ret.etag = cursor.getString(2); + ret.expires = cursor.getLong(3); + ret.mimeType = cursor.getString(4); + ret.encoding = cursor.getString(5); + ret.httpStatusCode = cursor.getInt(6); + ret.location = cursor.getString(7); + ret.contentLength = cursor.getLong(8); + return ret; + } + } finally { + if (cursor != null) cursor.close(); + } + return null; + } + + /** + * Remove a cache item. + * + * @param url The url + */ + void removeCache(String url) { + if (url == null || mCacheDatabase == null) { + return; + } + + mCacheDatabase.execSQL("DELETE FROM cache WHERE url = ?", new String[] { url }); + } + + /** + * Add or update a cache. CACHE_URL_COL is unique in the table. + * + * @param url The url + * @param c The CacheManager.CacheResult + */ + void addCache(String url, CacheResult c) { + if (url == null || mCacheDatabase == null) { + return; + } + + mCacheInserter.prepareForInsert(); + mCacheInserter.bind(mCacheUrlColIndex, url); + mCacheInserter.bind(mCacheFilePathColIndex, c.localPath); + mCacheInserter.bind(mCacheLastModifyColIndex, c.lastModified); + mCacheInserter.bind(mCacheETagColIndex, c.etag); + mCacheInserter.bind(mCacheExpiresColIndex, c.expires); + mCacheInserter.bind(mCacheMimeTypeColIndex, c.mimeType); + mCacheInserter.bind(mCacheEncodingColIndex, c.encoding); + mCacheInserter.bind(mCacheHttpStatusColIndex, c.httpStatusCode); + mCacheInserter.bind(mCacheLocationColIndex, c.location); + mCacheInserter.bind(mCacheContentLengthColIndex, c.contentLength); + mCacheInserter.execute(); + } + + /** + * Clear cache database + */ + void clearCache() { + if (mCacheDatabase == null) { + return; + } + + mCacheDatabase.delete("cache", null, null); + } + + boolean hasCache() { + if (mCacheDatabase == null) { + return false; + } + + Cursor cursor = mCacheDatabase.query("cache", ID_PROJECTION, + null, null, null, null, null); + boolean ret = cursor.moveToFirst() == true; + cursor.close(); + return ret; + } + + long getCacheTotalSize() { + long size = 0; + Cursor cursor = mCacheDatabase.rawQuery( + "SELECT SUM(contentlength) as sum FROM cache", null); + if (cursor.moveToFirst()) { + size = cursor.getLong(0); + } + cursor.close(); + return size; + } + + ArrayList<String> trimCache(long amount) { + ArrayList<String> pathList = new ArrayList<String>(100); + Cursor cursor = mCacheDatabase.rawQuery( + "SELECT contentlength, filepath FROM cache ORDER BY expires ASC", + null); + if (cursor.moveToFirst()) { + int batchSize = 100; + StringBuilder pathStr = new StringBuilder(20 + 16 * batchSize); + pathStr.append("DELETE FROM cache WHERE filepath IN (?"); + for (int i = 1; i < batchSize; i++) { + pathStr.append(", ?"); + } + pathStr.append(")"); + SQLiteStatement statement = mCacheDatabase.compileStatement(pathStr + .toString()); + // as bindString() uses 1-based index, initialize index to 1 + int index = 1; + do { + long length = cursor.getLong(0); + if (length == 0) { + continue; + } + amount -= length; + String filePath = cursor.getString(1); + statement.bindString(index, filePath); + pathList.add(filePath); + if (index++ == batchSize) { + statement.execute(); + statement.clearBindings(); + index = 1; + } + } while (cursor.moveToNext() && amount > 0); + if (index > 1) { + // there may be old bindings from the previous statement if + // index is less than batchSize, which is Ok. + statement.execute(); + } + statement.close(); + } + cursor.close(); + return pathList; + } + + // + // password functions + // + + /** + * Set password. Tuple (PASSWORD_HOST_COL, PASSWORD_USERNAME_COL) is unique. + * + * @param schemePlusHost The scheme and host for the password + * @param username The username for the password. If it is null, it means + * password can't be saved. + * @param password The password + */ + void setUsernamePassword(String schemePlusHost, String username, + String password) { + if (schemePlusHost == null || mDatabase == null) { + return; + } + + synchronized (mPasswordLock) { + final ContentValues c = new ContentValues(); + c.put(PASSWORD_HOST_COL, schemePlusHost); + c.put(PASSWORD_USERNAME_COL, username); + c.put(PASSWORD_PASSWORD_COL, password); + mDatabase.insert(mTableNames[TABLE_PASSWORD_ID], PASSWORD_HOST_COL, + c); + } + } + + /** + * Retrieve the username and password for a given host + * + * @param schemePlusHost The scheme and host which passwords applies to + * @return String[] if found, String[0] is username, which can be null and + * String[1] is password. Return null if it can't find anything. + */ + String[] getUsernamePassword(String schemePlusHost) { + if (schemePlusHost == null || mDatabase == null) { + return null; + } + + final String[] columns = new String[] { + PASSWORD_USERNAME_COL, PASSWORD_PASSWORD_COL + }; + final String selection = "(" + PASSWORD_HOST_COL + " == ?)"; + synchronized (mPasswordLock) { + String[] ret = null; + Cursor cursor = mDatabase.query(mTableNames[TABLE_PASSWORD_ID], + columns, selection, new String[] { schemePlusHost }, null, + null, null); + if (cursor.moveToFirst()) { + ret = new String[2]; + ret[0] = cursor.getString( + cursor.getColumnIndex(PASSWORD_USERNAME_COL)); + ret[1] = cursor.getString( + cursor.getColumnIndex(PASSWORD_PASSWORD_COL)); + } + cursor.close(); + return ret; + } + } + + /** + * Find out if there are any passwords saved. + * + * @return TRUE if there is passwords saved + */ + public boolean hasUsernamePassword() { + synchronized (mPasswordLock) { + return hasEntries(TABLE_PASSWORD_ID); + } + } + + /** + * Clear password database + */ + public void clearUsernamePassword() { + if (mDatabase == null) { + return; + } + + synchronized (mPasswordLock) { + mDatabase.delete(mTableNames[TABLE_PASSWORD_ID], null, null); + } + } + + // + // http authentication password functions + // + + /** + * Set HTTP authentication password. Tuple (HTTPAUTH_HOST_COL, + * HTTPAUTH_REALM_COL, HTTPAUTH_USERNAME_COL) is unique. + * + * @param host The host for the password + * @param realm The realm for the password + * @param username The username for the password. If it is null, it means + * password can't be saved. + * @param password The password + */ + void setHttpAuthUsernamePassword(String host, String realm, String username, + String password) { + if (host == null || realm == null || mDatabase == null) { + return; + } + + synchronized (mHttpAuthLock) { + final ContentValues c = new ContentValues(); + c.put(HTTPAUTH_HOST_COL, host); + c.put(HTTPAUTH_REALM_COL, realm); + c.put(HTTPAUTH_USERNAME_COL, username); + c.put(HTTPAUTH_PASSWORD_COL, password); + mDatabase.insert(mTableNames[TABLE_HTTPAUTH_ID], HTTPAUTH_HOST_COL, + c); + } + } + + /** + * Retrieve the HTTP authentication username and password for a given + * host+realm pair + * + * @param host The host the password applies to + * @param realm The realm the password applies to + * @return String[] if found, String[0] is username, which can be null and + * String[1] is password. Return null if it can't find anything. + */ + String[] getHttpAuthUsernamePassword(String host, String realm) { + if (host == null || realm == null || mDatabase == null){ + return null; + } + + final String[] columns = new String[] { + HTTPAUTH_USERNAME_COL, HTTPAUTH_PASSWORD_COL + }; + final String selection = "(" + HTTPAUTH_HOST_COL + " == ?) AND (" + + HTTPAUTH_REALM_COL + " == ?)"; + synchronized (mHttpAuthLock) { + String[] ret = null; + Cursor cursor = mDatabase.query(mTableNames[TABLE_HTTPAUTH_ID], + columns, selection, new String[] { host, realm }, null, + null, null); + if (cursor.moveToFirst()) { + ret = new String[2]; + ret[0] = cursor.getString( + cursor.getColumnIndex(HTTPAUTH_USERNAME_COL)); + ret[1] = cursor.getString( + cursor.getColumnIndex(HTTPAUTH_PASSWORD_COL)); + } + cursor.close(); + return ret; + } + } + + /** + * Find out if there are any HTTP authentication passwords saved. + * + * @return TRUE if there are passwords saved + */ + public boolean hasHttpAuthUsernamePassword() { + synchronized (mHttpAuthLock) { + return hasEntries(TABLE_HTTPAUTH_ID); + } + } + + /** + * Clear HTTP authentication password database + */ + public void clearHttpAuthUsernamePassword() { + if (mDatabase == null) { + return; + } + + synchronized (mHttpAuthLock) { + mDatabase.delete(mTableNames[TABLE_HTTPAUTH_ID], null, null); + } + } + + // + // form data functions + // + + /** + * Set form data for a site. Tuple (FORMDATA_URLID_COL, FORMDATA_NAME_COL, + * FORMDATA_VALUE_COL) is unique + * + * @param url The url of the site + * @param formdata The form data in HashMap + */ + void setFormData(String url, HashMap<String, String> formdata) { + if (url == null || formdata == null || mDatabase == null) { + return; + } + + final String selection = "(" + FORMURL_URL_COL + " == ?)"; + synchronized (mFormLock) { + long urlid = -1; + Cursor cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID], + ID_PROJECTION, selection, new String[] { url }, null, null, + null); + if (cursor.moveToFirst()) { + urlid = cursor.getLong(cursor.getColumnIndex(ID_COL)); + } else { + ContentValues c = new ContentValues(); + c.put(FORMURL_URL_COL, url); + urlid = mDatabase.insert( + mTableNames[TABLE_FORMURL_ID], null, c); + } + cursor.close(); + if (urlid >= 0) { + Set<Entry<String, String>> set = formdata.entrySet(); + Iterator<Entry<String, String>> iter = set.iterator(); + ContentValues map = new ContentValues(); + map.put(FORMDATA_URLID_COL, urlid); + while (iter.hasNext()) { + Entry<String, String> entry = iter.next(); + map.put(FORMDATA_NAME_COL, entry.getKey()); + map.put(FORMDATA_VALUE_COL, entry.getValue()); + mDatabase.insert(mTableNames[TABLE_FORMDATA_ID], null, map); + } + } + } + } + + /** + * Get all the values for a form entry with "name" in a given site + * + * @param url The url of the site + * @param name The name of the form entry + * @return A list of values. Return empty list if nothing is found. + */ + ArrayList<String> getFormData(String url, String name) { + ArrayList<String> values = new ArrayList<String>(); + if (url == null || name == null || mDatabase == null) { + return values; + } + + final String urlSelection = "(" + FORMURL_URL_COL + " == ?)"; + final String dataSelection = "(" + FORMDATA_URLID_COL + " == ?) AND (" + + FORMDATA_NAME_COL + " == ?)"; + synchronized (mFormLock) { + Cursor cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID], + ID_PROJECTION, urlSelection, new String[] { url }, null, + null, null); + if (cursor.moveToFirst()) { + long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL)); + Cursor dataCursor = mDatabase.query( + mTableNames[TABLE_FORMDATA_ID], + new String[] { ID_COL, FORMDATA_VALUE_COL }, + dataSelection, + new String[] { Long.toString(urlid), name }, null, + null, null); + if (dataCursor.moveToFirst()) { + int valueCol = + dataCursor.getColumnIndex(FORMDATA_VALUE_COL); + do { + values.add(dataCursor.getString(valueCol)); + } while (dataCursor.moveToNext()); + } + dataCursor.close(); + } + cursor.close(); + return values; + } + } + + /** + * Find out if there is form data saved. + * + * @return TRUE if there is form data in the database + */ + public boolean hasFormData() { + synchronized (mFormLock) { + return hasEntries(TABLE_FORMURL_ID); + } + } + + /** + * Clear form database + */ + public void clearFormData() { + if (mDatabase == null) { + return; + } + + synchronized (mFormLock) { + mDatabase.delete(mTableNames[TABLE_FORMURL_ID], null, null); + mDatabase.delete(mTableNames[TABLE_FORMDATA_ID], null, null); + } + } +} |