gecko/mobile/android/base/db/GeckoProvider.java.in

297 lines
9.7 KiB
Java
Raw Normal View History

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#filter substitution
package @ANDROID_PACKAGE_NAME@.db;
import java.io.File;
import java.io.IOException;
import java.lang.IllegalArgumentException;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Random;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoEventListener;
import org.mozilla.gecko.db.BrowserContract.CommonColumns;
import org.mozilla.gecko.db.DBUtils;
import org.mozilla.gecko.db.BrowserContract.Passwords;
import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
import org.mozilla.gecko.db.BrowserContract.SyncColumns;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.sqlite.SQLiteBridge;
import org.mozilla.gecko.sqlite.SQLiteBridgeException;
import org.mozilla.gecko.sync.Utils;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
/*
* Provides a basic ContentProvider that sets up and sends queries through
* SQLiteBridge. Content providers should extend this by setting the appropriate
* table and version numbers in onCreate, and implementing the abstract methods:
*
* public abstract String getTable(Uri uri);
* public abstract String getSortOrder(Uri uri, String aRequested);
* public abstract void setupDefaults(Uri uri, ContentValues values);
* public abstract void initGecko();
*/
public abstract class GeckoProvider extends ContentProvider {
private String mLogTag = "GeckoPasswordsProvider";
private String mDBName = "";
private int mDBVersion = 0;
private HashMap<String, SQLiteBridge> mDatabasePerProfile;
protected Context mContext = null;
protected void setLogTag(String aLogTag) {
mLogTag = aLogTag;
}
protected String getLogTag() {
return mLogTag;
}
protected void setDBName(String aDBName) {
mDBName = aDBName;
}
protected String getDBName() {
return mDBName;
}
protected void setDBVersion(int aVersion) {
mDBVersion = aVersion;
}
protected int getDBVersion() {
return mDBVersion;
}
private SQLiteBridge getDB(Context context, final String databasePath) {
SQLiteBridge bridge = null;
boolean dbNeedsSetup = true;
try {
String resourcePath = context.getPackageResourcePath();
GeckoAppShell.loadSQLiteLibs(context, resourcePath);
GeckoAppShell.loadNSSLibs(context, resourcePath);
2012-04-09 10:44:32 -07:00
bridge = new SQLiteBridge(databasePath);
int version = bridge.getVersion();
2012-04-09 10:44:32 -07:00
Log.i(mLogTag, version + " == " + mDBVersion);
dbNeedsSetup = version != mDBVersion;
2012-04-09 10:44:32 -07:00
} catch(SQLiteBridgeException ex) {
// this will throw if the database can't be found
// we should attempt to set it up if Gecko is running
dbNeedsSetup = true;
Log.e(mLogTag, "Error getting version ", ex);
// if Gecko is not running, we should bail out. Otherwise we try to
// let Gecko build the database for us
if (!GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning)) {
Log.e(mLogTag, "Can not set up database. Gecko is not running");
return null;
}
}
// If the database is not set up yet, or is the wrong schema version, we send an initialize
// call to Gecko. Gecko will handle building the database file correctly, as well as any
// migrations that are necessary
if (dbNeedsSetup) {
Log.i(mLogTag, "Sending init to gecko");
bridge = null;
initGecko();
}
2012-04-09 10:44:32 -07:00
mDatabasePerProfile.put(databasePath, bridge);
return bridge;
}
private SQLiteBridge getDatabaseForProfile(String profile) {
if (TextUtils.isEmpty(profile)) {
Log.d(mLogTag, "No profile provided, using default");
profile = BrowserContract.DEFAULT_PROFILE;
}
SQLiteBridge db = null;
synchronized (this) {
db = mDatabasePerProfile.get(profile);
if (db == null) {
db = getDB(mContext, getDatabasePathForProfile(profile));
}
}
Log.d(mLogTag, "Successfully created database helper for profile: " + profile);
return db;
}
private SQLiteBridge getDatabaseForPath(String profilePath) {
SQLiteBridge db = null;
synchronized (this) {
db = mDatabasePerProfile.get(profilePath);
if (db == null) {
File profileDir = new File(profilePath, mDBName);
db = getDB(mContext, profileDir.getPath());
}
}
Log.d(mLogTag, "Successfully created database helper for path: " + profilePath);
return db;
}
private String getDatabasePathForProfile(String profile) {
File profileDir = GeckoProfile.get(mContext, profile).getDir();
if (profileDir == null) {
Log.d(mLogTag, "Couldn't find directory for profile: " + profile);
return null;
}
Log.d(mLogTag, "Using path: " + profileDir.getPath());
String databasePath = new File(profileDir, mDBName).getAbsolutePath();
return databasePath;
}
private SQLiteBridge getDatabase(Uri uri) {
String profile = null;
String profilePath = null;
profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE);
profilePath = uri.getQueryParameter(BrowserContract.PARAM_PROFILE_PATH);
// Testing will specify the absolute profile path
if (profilePath != null)
return getDatabaseForPath(profilePath);
return getDatabaseForProfile(profile);
}
@Override
public boolean onCreate() {
mContext = getContext();
synchronized (this) {
mDatabasePerProfile = new HashMap<String, SQLiteBridge>();
}
return true;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int deleted = 0;
final SQLiteBridge db = getDatabase(uri);
if (db == null)
return deleted;
try {
deleted = db.delete(getTable(uri), selection, selectionArgs);
} catch (SQLiteBridgeException ex) {
Log.e(mLogTag, "Error deleting record", ex);
}
return deleted;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
long id = -1;
final SQLiteBridge db = getDatabase(uri);
// If we can not get a SQLiteBridge instance, its likely that the database
// has not been set up and Gecko is not running. We return null and expect
// callers to try again later
if (db == null)
return null;
setupDefaults(uri, values);
2012-04-09 10:44:32 -07:00
onPreInsert(values, uri, db);
try {
id = db.insert(getTable(uri), null, values);
2012-04-09 10:44:32 -07:00
} catch(SQLiteBridgeException ex) {
Log.e(mLogTag, "Error inserting in db", ex);
}
return ContentUris.withAppendedId(uri, id);
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int updated = 0;
final SQLiteBridge db = getDatabase(uri);
// If we can not get a SQLiteBridge instance, its likely that the database
// has not been set up and Gecko is not running. We return null and expect
// callers to try again later
if (db == null)
return updated;
onPreUpdate(values, uri, db);
try {
updated = db.update(getTable(uri), values, selection, selectionArgs);
2012-04-09 10:44:32 -07:00
} catch(SQLiteBridgeException ex) {
Log.e(mLogTag, "Error updating table", ex);
}
return updated;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Cursor cursor = null;
final SQLiteBridge db = getDatabase(uri);
// If we can not get a SQLiteBridge instance, its likely that the database
// has not been set up and Gecko is not running. We return null and expect
// callers to try again later
if (db == null)
return cursor;
sortOrder = getSortOrder(uri, sortOrder);
try {
cursor = db.query(getTable(uri), projection, selection, selectionArgs, null, null, sortOrder, null);
onPostQuery(cursor, uri, db);
} catch (SQLiteBridgeException ex) {
Log.e(mLogTag, "Error querying database", ex);
}
return cursor;
}
public abstract String getTable(Uri uri);
public abstract String getSortOrder(Uri uri, String aRequested);
public abstract void setupDefaults(Uri uri, ContentValues values);
public abstract void initGecko();
public abstract void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db);
public abstract void onPreUpdate(ContentValues values, Uri uri, SQLiteBridge db);
public abstract void onPostQuery(Cursor cursor, Uri uri, SQLiteBridge db);
}