Merge "Create WebViewDatabaseClassic from WebViewDatabase." into jb-dev
This commit is contained in:
@@ -72,7 +72,7 @@ class BrowserFrame extends Handler {
|
||||
private final CallbackProxy mCallbackProxy;
|
||||
private final WebSettingsClassic mSettings;
|
||||
private final Context mContext;
|
||||
private final WebViewDatabase mDatabase;
|
||||
private final WebViewDatabaseClassic mDatabase;
|
||||
private final WebViewCore mWebViewCore;
|
||||
/* package */ boolean mLoadInitFromJava;
|
||||
private int mLoadType;
|
||||
@@ -241,7 +241,7 @@ class BrowserFrame extends Handler {
|
||||
mSettings = settings;
|
||||
mContext = context;
|
||||
mCallbackProxy = proxy;
|
||||
mDatabase = WebViewDatabase.getInstance(appContext);
|
||||
mDatabase = WebViewDatabaseClassic.getInstance(appContext);
|
||||
mWebViewCore = w;
|
||||
|
||||
mSearchBox = new SearchBoxImpl(mWebViewCore, mCallbackProxy);
|
||||
@@ -496,8 +496,8 @@ class BrowserFrame extends Handler {
|
||||
if (item != null) {
|
||||
WebAddress uri = new WebAddress(item.getUrl());
|
||||
String schemePlusHost = uri.getScheme() + uri.getHost();
|
||||
String[] up =
|
||||
mDatabase.getUsernamePassword(schemePlusHost);
|
||||
String[] up = mDatabase.getUsernamePassword(
|
||||
schemePlusHost);
|
||||
if (up != null && up[0] != null) {
|
||||
setUsernamePassword(up[0], up[1]);
|
||||
}
|
||||
@@ -809,8 +809,7 @@ class BrowserFrame extends Handler {
|
||||
// non-null username implies that user has
|
||||
// chosen to save password, so update the
|
||||
// recorded password
|
||||
mDatabase.setUsernamePassword(
|
||||
schemePlusHost, username, password);
|
||||
mDatabase.setUsernamePassword(schemePlusHost, username, password);
|
||||
}
|
||||
} else {
|
||||
// CallbackProxy will handle creating the resume
|
||||
|
||||
@@ -701,7 +701,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
// A final CallbackProxy shared by WebViewCore and BrowserFrame.
|
||||
private CallbackProxy mCallbackProxy;
|
||||
|
||||
private WebViewDatabase mDatabase;
|
||||
private WebViewDatabaseClassic mDatabase;
|
||||
|
||||
// SSL certificate for the main top-level page (if secure)
|
||||
private SslCertificate mCertificate;
|
||||
@@ -1230,7 +1230,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
mViewManager = new ViewManager(this);
|
||||
L10nUtils.setApplicationContext(context.getApplicationContext());
|
||||
mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces);
|
||||
mDatabase = WebViewDatabase.getInstance(context);
|
||||
mDatabase = WebViewDatabaseClassic.getInstance(context);
|
||||
mScroller = new OverScroller(context, null, 0, 0, false); //TODO Use OverScroller's flywheel
|
||||
mZoomManager = new ZoomManager(this, mCallbackProxy);
|
||||
|
||||
@@ -1294,6 +1294,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
public WebStorage getWebStorage() {
|
||||
return WebStorageClassic.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebViewDatabase getWebViewDatabase(Context context) {
|
||||
return WebViewDatabaseClassic.getInstance(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void onHandleUiEvent(MotionEvent event, int eventType, int flags) {
|
||||
@@ -7192,8 +7197,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
break;
|
||||
}
|
||||
case NEVER_REMEMBER_PASSWORD: {
|
||||
mDatabase.setUsernamePassword(
|
||||
msg.getData().getString("host"), null, null);
|
||||
mDatabase.setUsernamePassword(msg.getData().getString("host"), null, null);
|
||||
((Message) msg.obj).sendToTarget();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16,611 +16,79 @@
|
||||
|
||||
package android.webkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
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.SQLiteException;
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class allows developers to determine whether any WebView used in the
|
||||
* application has stored any of the following types of browsing data and
|
||||
* to clear any such stored data for all WebViews in the application.
|
||||
* <ul>
|
||||
* <li>Username/password pairs entered into web forms</li>
|
||||
* <li>HTTP authentication username/password pairs</li>
|
||||
* <li>Data entered into text fields (e.g. for autocomplete suggestions)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WebViewDatabase {
|
||||
private static final String DATABASE_FILE = "webview.db";
|
||||
private static final String CACHE_DATABASE_FILE = "webviewCache.db";
|
||||
|
||||
// log tag
|
||||
// TODO: deprecate/hide this.
|
||||
protected static final String LOGTAG = "webviewdatabase";
|
||||
|
||||
private static final int DATABASE_VERSION = 11;
|
||||
// 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
|
||||
// 9 -> 10 Update httpauth table UNIQUE
|
||||
// 10 -> 11 Drop cookies and cache now managed by the chromium stack,
|
||||
// and update the form data table to use the new format
|
||||
// implemented for b/5265606.
|
||||
|
||||
private static WebViewDatabase mInstance = null;
|
||||
|
||||
private static SQLiteDatabase mDatabase = null;
|
||||
|
||||
// synchronize locks
|
||||
private final Object mPasswordLock = new Object();
|
||||
private final Object mFormLock = new Object();
|
||||
private final Object mHttpAuthLock = new Object();
|
||||
|
||||
private static final String mTableNames[] = {
|
||||
"password", "formurl", "formdata", "httpauth"
|
||||
};
|
||||
|
||||
// Table ids (they are index to mTableNames)
|
||||
private static final int TABLE_PASSWORD_ID = 0;
|
||||
private static final int TABLE_FORMURL_ID = 1;
|
||||
private static final int TABLE_FORMDATA_ID = 2;
|
||||
private static final int TABLE_HTTPAUTH_ID = 3;
|
||||
|
||||
// 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 "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";
|
||||
|
||||
// Initially true until the background thread completes.
|
||||
private boolean mInitialized = false;
|
||||
|
||||
private WebViewDatabase(final Context context) {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
init(context);
|
||||
}
|
||||
}.start();
|
||||
|
||||
// Singleton only, use getInstance()
|
||||
/**
|
||||
* @hide Only for use by WebViewProvider implementations.
|
||||
*/
|
||||
protected WebViewDatabase() {
|
||||
}
|
||||
|
||||
public static synchronized WebViewDatabase getInstance(Context context) {
|
||||
if (mInstance == null) {
|
||||
mInstance = new WebViewDatabase(context);
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
private synchronized void init(Context context) {
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
initDatabase(context);
|
||||
// Before using the Chromium HTTP stack, we stored the WebKit cache in
|
||||
// our own DB. Clean up the DB file if it's still around.
|
||||
context.deleteDatabase(CACHE_DATABASE_FILE);
|
||||
|
||||
// Thread done, notify.
|
||||
mInitialized = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
private void initDatabase(Context context) {
|
||||
try {
|
||||
mDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0, null);
|
||||
} catch (SQLiteException e) {
|
||||
// try again by deleting the old db and create a new one
|
||||
if (context.deleteDatabase(DATABASE_FILE)) {
|
||||
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) {
|
||||
mInitialized = true;
|
||||
notify();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDatabase.getVersion() != DATABASE_VERSION) {
|
||||
mDatabase.beginTransactionNonExclusive();
|
||||
try {
|
||||
upgradeDatabase();
|
||||
mDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
mDatabase.endTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void upgradeDatabase() {
|
||||
upgradeDatabaseToV10();
|
||||
upgradeDatabaseFromV10ToV11();
|
||||
// Add future database upgrade functions here, one version at a
|
||||
// time.
|
||||
mDatabase.setVersion(DATABASE_VERSION);
|
||||
}
|
||||
|
||||
private static void upgradeDatabaseFromV10ToV11() {
|
||||
int oldVersion = mDatabase.getVersion();
|
||||
|
||||
if (oldVersion >= 11) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear out old java stack cookies - this data is now stored in
|
||||
// a separate database managed by the Chrome stack.
|
||||
mDatabase.execSQL("DROP TABLE IF EXISTS cookies");
|
||||
|
||||
// Likewise for the old cache table.
|
||||
mDatabase.execSQL("DROP TABLE IF EXISTS cache");
|
||||
|
||||
// Update form autocomplete URLs to match new ICS formatting.
|
||||
Cursor c = mDatabase.query(mTableNames[TABLE_FORMURL_ID], null, null,
|
||||
null, null, null, null);
|
||||
while (c.moveToNext()) {
|
||||
String urlId = Long.toString(c.getLong(c.getColumnIndex(ID_COL)));
|
||||
String url = c.getString(c.getColumnIndex(FORMURL_URL_COL));
|
||||
ContentValues cv = new ContentValues(1);
|
||||
cv.put(FORMURL_URL_COL, WebTextView.urlForAutoCompleteData(url));
|
||||
mDatabase.update(mTableNames[TABLE_FORMURL_ID], cv, ID_COL + "=?",
|
||||
new String[] { urlId });
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
|
||||
private static void upgradeDatabaseToV10() {
|
||||
int oldVersion = mDatabase.getVersion();
|
||||
|
||||
if (oldVersion >= 10) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldVersion != 0) {
|
||||
Log.i(LOGTAG, "Upgrading database from version "
|
||||
+ oldVersion + " to "
|
||||
+ DATABASE_VERSION + ", which will destroy old data");
|
||||
}
|
||||
|
||||
if (9 == oldVersion) {
|
||||
mDatabase.execSQL("DROP TABLE IF EXISTS "
|
||||
+ mTableNames[TABLE_HTTPAUTH_ID]);
|
||||
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
|
||||
+ ") ON CONFLICT REPLACE);");
|
||||
return;
|
||||
}
|
||||
|
||||
mDatabase.execSQL("DROP TABLE IF EXISTS cookies");
|
||||
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]);
|
||||
|
||||
// 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
|
||||
+ ") 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);");
|
||||
}
|
||||
|
||||
// Wait for the background initialization thread to complete and check the
|
||||
// database creation status.
|
||||
private boolean checkInitialized() {
|
||||
synchronized (this) {
|
||||
while (!mInitialized) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(LOGTAG, "Caught exception while checking " +
|
||||
"initialization");
|
||||
Log.e(LOGTAG, Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
return mDatabase != null;
|
||||
}
|
||||
|
||||
private boolean hasEntries(int tableId) {
|
||||
if (!checkInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Cursor cursor = null;
|
||||
boolean ret = false;
|
||||
try {
|
||||
cursor = mDatabase.query(mTableNames[tableId], ID_PROJECTION,
|
||||
null, null, null, null, null);
|
||||
ret = cursor.moveToFirst() == true;
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "hasEntries", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 || !checkInitialized()) {
|
||||
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);
|
||||
}
|
||||
return WebViewFactory.getProvider().getWebViewDatabase(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the username and password for a given host
|
||||
* Gets whether there are any username/password combinations
|
||||
* from web pages saved.
|
||||
*
|
||||
* @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 || !checkInitialized()) {
|
||||
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 = null;
|
||||
try {
|
||||
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));
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getUsernamePassword", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there are any passwords saved.
|
||||
*
|
||||
* @return TRUE if there is passwords saved
|
||||
* @return true if there are any username/passwords used in web
|
||||
* forms saved
|
||||
*/
|
||||
public boolean hasUsernamePassword() {
|
||||
synchronized (mPasswordLock) {
|
||||
return hasEntries(TABLE_PASSWORD_ID);
|
||||
}
|
||||
throw new MustOverrideException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear password database
|
||||
* Clears any username/password combinations saved from web forms.
|
||||
*/
|
||||
public void clearUsernamePassword() {
|
||||
if (!checkInitialized()) {
|
||||
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 || !checkInitialized()) {
|
||||
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);
|
||||
}
|
||||
throw new MustOverrideException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the HTTP authentication username and password for a given
|
||||
* host+realm pair
|
||||
* Gets whether there are any HTTP authentication username/password combinations saved.
|
||||
*
|
||||
* @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 || !checkInitialized()){
|
||||
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 = null;
|
||||
try {
|
||||
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));
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getHttpAuthUsernamePassword", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there are any HTTP authentication passwords saved.
|
||||
*
|
||||
* @return TRUE if there are passwords saved
|
||||
* @return true if there are any HTTP authentication username/passwords saved
|
||||
*/
|
||||
public boolean hasHttpAuthUsernamePassword() {
|
||||
synchronized (mHttpAuthLock) {
|
||||
return hasEntries(TABLE_HTTPAUTH_ID);
|
||||
}
|
||||
throw new MustOverrideException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear HTTP authentication password database
|
||||
* Clears any HTTP authentication username/passwords that are saved.
|
||||
*/
|
||||
public void clearHttpAuthUsernamePassword() {
|
||||
if (!checkInitialized()) {
|
||||
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 || !checkInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String selection = "(" + FORMURL_URL_COL + " == ?)";
|
||||
synchronized (mFormLock) {
|
||||
long urlid = -1;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
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);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "setFormData", e);
|
||||
} finally {
|
||||
if (cursor != null) 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new MustOverrideException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the values for a form entry with "name" in a given site
|
||||
* Gets whether there is any previously-entered form data saved.
|
||||
*
|
||||
* @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 || !checkInitialized()) {
|
||||
return values;
|
||||
}
|
||||
|
||||
final String urlSelection = "(" + FORMURL_URL_COL + " == ?)";
|
||||
final String dataSelection = "(" + FORMDATA_URLID_COL + " == ?) AND ("
|
||||
+ FORMDATA_NAME_COL + " == ?)";
|
||||
synchronized (mFormLock) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = mDatabase.query(mTableNames[TABLE_FORMURL_ID],
|
||||
ID_PROJECTION, urlSelection, new String[] { url }, null,
|
||||
null, null);
|
||||
while (cursor.moveToNext()) {
|
||||
long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
|
||||
Cursor dataCursor = null;
|
||||
try {
|
||||
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());
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getFormData dataCursor", e);
|
||||
} finally {
|
||||
if (dataCursor != null) dataCursor.close();
|
||||
}
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getFormData cursor", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if there is form data saved.
|
||||
*
|
||||
* @return TRUE if there is form data in the database
|
||||
* @return true if there is form data saved
|
||||
*/
|
||||
public boolean hasFormData() {
|
||||
synchronized (mFormLock) {
|
||||
return hasEntries(TABLE_FORMURL_ID);
|
||||
}
|
||||
throw new MustOverrideException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear form database
|
||||
* Clears any stored previously-entered form data.
|
||||
*/
|
||||
public void clearFormData() {
|
||||
if (!checkInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mFormLock) {
|
||||
mDatabase.delete(mTableNames[TABLE_FORMURL_ID], null, null);
|
||||
mDatabase.delete(mTableNames[TABLE_FORMDATA_ID], null, null);
|
||||
}
|
||||
throw new MustOverrideException();
|
||||
}
|
||||
}
|
||||
|
||||
624
core/java/android/webkit/WebViewDatabaseClassic.java
Normal file
624
core/java/android/webkit/WebViewDatabaseClassic.java
Normal file
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.List;
|
||||
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.SQLiteException;
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
import android.util.Log;
|
||||
|
||||
final class WebViewDatabaseClassic extends WebViewDatabase {
|
||||
private static final String LOGTAG = "WebViewDatabaseClassic";
|
||||
private static final String DATABASE_FILE = "webview.db";
|
||||
private static final String CACHE_DATABASE_FILE = "webviewCache.db";
|
||||
|
||||
private static final int DATABASE_VERSION = 11;
|
||||
// 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
|
||||
// 9 -> 10 Update httpauth table UNIQUE
|
||||
// 10 -> 11 Drop cookies and cache now managed by the chromium stack,
|
||||
// and update the form data table to use the new format
|
||||
// implemented for b/5265606.
|
||||
|
||||
private static WebViewDatabaseClassic sInstance = null;
|
||||
|
||||
private static SQLiteDatabase sDatabase = null;
|
||||
|
||||
// synchronize locks
|
||||
private final Object mPasswordLock = new Object();
|
||||
private final Object mFormLock = new Object();
|
||||
private final Object mHttpAuthLock = new Object();
|
||||
|
||||
private static final String mTableNames[] = {
|
||||
"password", "formurl", "formdata", "httpauth"
|
||||
};
|
||||
|
||||
// Table ids (they are index to mTableNames)
|
||||
private static final int TABLE_PASSWORD_ID = 0;
|
||||
private static final int TABLE_FORMURL_ID = 1;
|
||||
private static final int TABLE_FORMDATA_ID = 2;
|
||||
private static final int TABLE_HTTPAUTH_ID = 3;
|
||||
|
||||
// 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 "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";
|
||||
|
||||
// Initially true until the background thread completes.
|
||||
private boolean mInitialized = false;
|
||||
|
||||
WebViewDatabaseClassic(final Context context) {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
init(context);
|
||||
}
|
||||
}.start();
|
||||
|
||||
// Singleton only, use getInstance()
|
||||
}
|
||||
|
||||
public static synchronized WebViewDatabaseClassic getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new WebViewDatabaseClassic(context);
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private synchronized void init(Context context) {
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
initDatabase(context);
|
||||
// Before using the Chromium HTTP stack, we stored the WebKit cache in
|
||||
// our own DB. Clean up the DB file if it's still around.
|
||||
context.deleteDatabase(CACHE_DATABASE_FILE);
|
||||
|
||||
// Thread done, notify.
|
||||
mInitialized = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
private void initDatabase(Context context) {
|
||||
try {
|
||||
sDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0, null);
|
||||
} catch (SQLiteException e) {
|
||||
// try again by deleting the old db and create a new one
|
||||
if (context.deleteDatabase(DATABASE_FILE)) {
|
||||
sDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0,
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
// sDatabase should not be null,
|
||||
// the only case is RequestAPI test has problem to create db
|
||||
if (sDatabase == null) {
|
||||
mInitialized = true;
|
||||
notify();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sDatabase.getVersion() != DATABASE_VERSION) {
|
||||
sDatabase.beginTransactionNonExclusive();
|
||||
try {
|
||||
upgradeDatabase();
|
||||
sDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
sDatabase.endTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void upgradeDatabase() {
|
||||
upgradeDatabaseToV10();
|
||||
upgradeDatabaseFromV10ToV11();
|
||||
// Add future database upgrade functions here, one version at a
|
||||
// time.
|
||||
sDatabase.setVersion(DATABASE_VERSION);
|
||||
}
|
||||
|
||||
private static void upgradeDatabaseFromV10ToV11() {
|
||||
int oldVersion = sDatabase.getVersion();
|
||||
|
||||
if (oldVersion >= 11) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear out old java stack cookies - this data is now stored in
|
||||
// a separate database managed by the Chrome stack.
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS cookies");
|
||||
|
||||
// Likewise for the old cache table.
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS cache");
|
||||
|
||||
// Update form autocomplete URLs to match new ICS formatting.
|
||||
Cursor c = sDatabase.query(mTableNames[TABLE_FORMURL_ID], null, null,
|
||||
null, null, null, null);
|
||||
while (c.moveToNext()) {
|
||||
String urlId = Long.toString(c.getLong(c.getColumnIndex(ID_COL)));
|
||||
String url = c.getString(c.getColumnIndex(FORMURL_URL_COL));
|
||||
ContentValues cv = new ContentValues(1);
|
||||
cv.put(FORMURL_URL_COL, WebTextView.urlForAutoCompleteData(url));
|
||||
sDatabase.update(mTableNames[TABLE_FORMURL_ID], cv, ID_COL + "=?",
|
||||
new String[] { urlId });
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
|
||||
private static void upgradeDatabaseToV10() {
|
||||
int oldVersion = sDatabase.getVersion();
|
||||
|
||||
if (oldVersion >= 10) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldVersion != 0) {
|
||||
Log.i(LOGTAG, "Upgrading database from version "
|
||||
+ oldVersion + " to "
|
||||
+ DATABASE_VERSION + ", which will destroy old data");
|
||||
}
|
||||
|
||||
if (9 == oldVersion) {
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS "
|
||||
+ mTableNames[TABLE_HTTPAUTH_ID]);
|
||||
sDatabase.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
|
||||
+ ") ON CONFLICT REPLACE);");
|
||||
return;
|
||||
}
|
||||
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS cookies");
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS cache");
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS "
|
||||
+ mTableNames[TABLE_FORMURL_ID]);
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS "
|
||||
+ mTableNames[TABLE_FORMDATA_ID]);
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS "
|
||||
+ mTableNames[TABLE_HTTPAUTH_ID]);
|
||||
sDatabase.execSQL("DROP TABLE IF EXISTS "
|
||||
+ mTableNames[TABLE_PASSWORD_ID]);
|
||||
|
||||
// formurl
|
||||
sDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_FORMURL_ID]
|
||||
+ " (" + ID_COL + " INTEGER PRIMARY KEY, " + FORMURL_URL_COL
|
||||
+ " TEXT" + ");");
|
||||
|
||||
// formdata
|
||||
sDatabase.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
|
||||
sDatabase.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
|
||||
+ ") ON CONFLICT REPLACE);");
|
||||
// passwords
|
||||
sDatabase.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);");
|
||||
}
|
||||
|
||||
// Wait for the background initialization thread to complete and check the
|
||||
// database creation status.
|
||||
private boolean checkInitialized() {
|
||||
synchronized (this) {
|
||||
while (!mInitialized) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(LOGTAG, "Caught exception while checking " +
|
||||
"initialization");
|
||||
Log.e(LOGTAG, Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sDatabase != null;
|
||||
}
|
||||
|
||||
private boolean hasEntries(int tableId) {
|
||||
if (!checkInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Cursor cursor = null;
|
||||
boolean ret = false;
|
||||
try {
|
||||
cursor = sDatabase.query(mTableNames[tableId], ID_PROJECTION,
|
||||
null, null, null, null, null);
|
||||
ret = cursor.moveToFirst() == true;
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "hasEntries", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 || !checkInitialized()) {
|
||||
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);
|
||||
sDatabase.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 || !checkInitialized()) {
|
||||
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 = null;
|
||||
try {
|
||||
cursor = sDatabase.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));
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getUsernamePassword", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WebViewDatabase#hasUsernamePassword
|
||||
*/
|
||||
@Override
|
||||
public boolean hasUsernamePassword() {
|
||||
synchronized (mPasswordLock) {
|
||||
return hasEntries(TABLE_PASSWORD_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WebViewDatabase#clearUsernamePassword
|
||||
*/
|
||||
@Override
|
||||
public void clearUsernamePassword() {
|
||||
if (!checkInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mPasswordLock) {
|
||||
sDatabase.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 || !checkInitialized()) {
|
||||
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);
|
||||
sDatabase.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 || !checkInitialized()){
|
||||
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 = null;
|
||||
try {
|
||||
cursor = sDatabase.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));
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getHttpAuthUsernamePassword", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WebViewDatabase#hasHttpAuthUsernamePassword
|
||||
*/
|
||||
@Override
|
||||
public boolean hasHttpAuthUsernamePassword() {
|
||||
synchronized (mHttpAuthLock) {
|
||||
return hasEntries(TABLE_HTTPAUTH_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WebViewDatabase#clearHttpAuthUsernamePassword
|
||||
*/
|
||||
@Override
|
||||
public void clearHttpAuthUsernamePassword() {
|
||||
if (!checkInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mHttpAuthLock) {
|
||||
sDatabase.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 || !checkInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String selection = "(" + FORMURL_URL_COL + " == ?)";
|
||||
synchronized (mFormLock) {
|
||||
long urlid = -1;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = sDatabase.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 = sDatabase.insert(
|
||||
mTableNames[TABLE_FORMURL_ID], null, c);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "setFormData", e);
|
||||
} finally {
|
||||
if (cursor != null) 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());
|
||||
sDatabase.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 || !checkInitialized()) {
|
||||
return values;
|
||||
}
|
||||
|
||||
final String urlSelection = "(" + FORMURL_URL_COL + " == ?)";
|
||||
final String dataSelection = "(" + FORMDATA_URLID_COL + " == ?) AND ("
|
||||
+ FORMDATA_NAME_COL + " == ?)";
|
||||
synchronized (mFormLock) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = sDatabase.query(mTableNames[TABLE_FORMURL_ID],
|
||||
ID_PROJECTION, urlSelection, new String[] { url }, null,
|
||||
null, null);
|
||||
while (cursor.moveToNext()) {
|
||||
long urlid = cursor.getLong(cursor.getColumnIndex(ID_COL));
|
||||
Cursor dataCursor = null;
|
||||
try {
|
||||
dataCursor = sDatabase.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());
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getFormData dataCursor", e);
|
||||
} finally {
|
||||
if (dataCursor != null) dataCursor.close();
|
||||
}
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(LOGTAG, "getFormData cursor", e);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WebViewDatabase#hasFormData
|
||||
*/
|
||||
@Override
|
||||
public boolean hasFormData() {
|
||||
synchronized (mFormLock) {
|
||||
return hasEntries(TABLE_FORMURL_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WebViewDatabase#clearFormData
|
||||
*/
|
||||
@Override
|
||||
public void clearFormData() {
|
||||
if (!checkInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mFormLock) {
|
||||
sDatabase.delete(mTableNames[TABLE_FORMURL_ID], null, null);
|
||||
sDatabase.delete(mTableNames[TABLE_FORMDATA_ID], null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.webkit;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* This is the main entry-point into the WebView back end implementations, which the WebView
|
||||
* proxy class uses to instantiate all the other objects as needed. The backend must provide an
|
||||
@@ -63,21 +65,32 @@ public interface WebViewFactoryProvider {
|
||||
/**
|
||||
* Gets the singleton CookieManager instance for this WebView implementation. The
|
||||
* implementation must return the same instance on subsequent calls.
|
||||
* @return the singleton CookieManager instance.
|
||||
*
|
||||
* @return the singleton CookieManager instance
|
||||
*/
|
||||
CookieManager getCookieManager();
|
||||
|
||||
/**
|
||||
* Gets the singleton WebIconDatabase instance for this WebView implementation. The
|
||||
* implementation must return the same instance on subsequent calls.
|
||||
* @return the singleton WebIconDatabase instance.
|
||||
*
|
||||
* @return the singleton WebIconDatabase instance
|
||||
*/
|
||||
WebIconDatabase getWebIconDatabase();
|
||||
|
||||
/**
|
||||
* Gets the singleton WebStorage instance for this WebView implementation. The
|
||||
* implementation must return the same instance on subsequent calls.
|
||||
* @return the singleton WebStorage instance.
|
||||
*
|
||||
* @return the singleton WebStorage instance
|
||||
*/
|
||||
WebStorage getWebStorage();
|
||||
|
||||
/**
|
||||
* Gets the singleton WebViewDatabase instance for this WebView implementation. The
|
||||
* implementation must return the same instance on subsequent calls.
|
||||
*
|
||||
* @return the singleton WebViewDatabase instance
|
||||
*/
|
||||
WebViewDatabase getWebViewDatabase(Context context);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user