can i specify a path to sqlite database - android

I created sqlite database in android as shown in the code below and i added some records to it. then i wanted to copy that database to use it in anothe
application, my database is called "GEOLOC.db" and i searched for it but it was not found despite it contains data.
please let me know
1-how to know where the sqlite database is saved
2-can i specify a path to which the databse will be saved?
code:
public class SQLiteHelper extends SQLiteOpenHelper {
private final String TAG = this.getClass().getSimpleName();
private static final int DATABASE_VERSION = 2;
private static final String DATABASE_NAME = "GEOLOC.db";//can i specify a pth here??
private static final String DATABASE_TABLE_NAME = "NODE_00";
private Context mCtx = null;
public SQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.mCtx = context;
}

Usually, a particular sqlite database is specific to one single application. However you won't be able to view it unless the phone is rooted. In fact it is normally found in the following path:
//data/data/<Your-Application-Package-Name>/databases/<your-database-name>
The application package name can be accessed using the following code:
PACKAGE_NAME = getApplicationContext().getPackageName();
The database name is stored in the class which extends the SQLiteOpenHelperthrough the following declaration:
private static final String DATABASE_NAME = "buspass";
In order to share data between apps (provied that they have both been developed by you), you will need to specify a shared user id in the Manifest file of both apps.
Use the same DBAdapter in both apps. In the app that hosts the database, call the DBAdapter with the native context.
DBadapter hostDBAdapter = new DbAdapter(getApplicationContext());
performerDBadapter.open();
In the second app, access the database with the context of the database hosting app.
First, define the shared context:
Context sharedContext = null;
try {
sharedContext = this.createPackageContext("replace.with.host.package.name", Context.CONTEXT_INCLUDE_CODE);
if (sharedContext == null) {
return;
}
} catch (Exception e) {
String error = e.getMessage();
return;
}
Then open the DBAdapter with the shared context:
DbAdapter sharedDBadapter = new PerformerDbAdapter(sharedContext);
sharedDBadapter.open();
The manifest file should have the following code:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:sharedUserId="my.app" ... >
Hope this helps :)

Related

SQLCipher Android is not throwing an exception with incorrect password

I am using SQLCipher v3.5.7 and observed an unexpected behavior from SQLiteDatabase with incorrect password.
I encrypted the database with "key1".
Closed the database connection.
Then I tried to open my database with "key2", the SQLiteDatabase is not throwing an exception. Instead, it is updating the old password (key1) to new password (key2). I verified this by opening the .db file in SQLiteBrowser.
Can somebody help me why it is behaving this way?
private static SQLiteCipherDatabaseHelper createDBConnection(Context context, String databasePath, final String key) throws SQLiteDatabaseException {
if (dbInstance == null) {
dbInstance = new SQLiteCipherDatabaseHelper(context, databasePath);
String path = context.getDatabasePath(databasePath).getPath();
File dbPathFile = new File(path);
if (!dbPathFile.exists()) {
dbPathFile.getParentFile().mkdirs();
}
setDatabaseWithDBEncryption(key);
}
return dbInstance;
}
private static void setDatabaseWithDBEncryption(String encryptionKey) throws SQLiteDatabaseException {
loadSQLCipherLibs();
try {
sqliteDatabase = SQLiteDatabase.openOrCreateDatabase(new File(context.getDatabasePath(databasePath).getPath()), encryptionKey, null);
} catch (Exception e) {
SyncLogger.getSharedInstance().logFatal("SQLiteCipherDatabaseHelper", "Failed to open or create database. Please provide a valid encryption key");
throw new SQLiteDatabaseException(SyncErrorCodes.EC_DB_SQLCIPHER_FAILED_TO_OPEN_OR_CREATE_DATABASE, SyncErrorDomains.ED_OFFLINE_OBJECTS, SyncErrorMessages.EM_DB_SQLCIPHER_FAILED_TO_OPEN_OR_CREATE_DATABASE, e);
}
}
Have you upgrade your db version ??
private static final int DATABASE_VERSION = 2;//from 1 to 2
private static class OpenHelper extends SQLiteOpenHelper {
OpenHelper(Context context) // constructor
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
//Changes in db mentioned here
}
}
Are you actually populating the database with tables and data after keying it? It seems most likely that for some reason you are recreating the database each time you run the test. Have you verified that the actual database is encrypted by pulling it off the device and examining the file? Perhaps you are recreating a new database each time you run the test, in which case the new key would just be used.
It's worth noting that this behavior is covered in the SQLCipher for Android Test project.
https://github.com/sqlcipher/sqlcipher-android-tests/blob/master/src/main/java/net/zetetic/tests/InvalidPasswordTest.java
If you suspect an issue you can try running the test suite on your device, or create a new test case to verify the behavior with your own code.

Is there a better way to pre-load items into a database?

In my Android app I have a
SQLiteHelper class that extends SQLIteOpenHelper, and takes care of things like table-creation and upgrades.
SQLiteDatasource class that performs CRUD operations on the SQLiteHelper object.
I want to pre-load one of the tables with certain items so there is something present when the user first uses the app. These items may change so I want to make them modular.
Right now I am doing it this way:
public class MyDefaults {
public static final ArrayList<HashMap<String, String>> MY_DEFAULTS;
static {
MY_DEFAULTS = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map = new HashMap<String, String>();
//All the values below you change to whatever defaults you want
map.clear();
map.put(SQLiteHelper.KEY_1, "Value 1A");
map.put(SQLiteHelper.KEY_2, "Value 2A");
map.put(SQLiteHelper.KEY_3, "Value 3A");
MY_DEFAULTS.add(new HashMap<String, String>(map));
map.clear();
map.put(SQLiteHelper.KEY_1, "Value 1B");
map.put(SQLiteHelper.KEY_2, "Value 2B");
map.put(SQLiteHelper.KEY_3, "Value 3B");
MY_DEFAULTS.add(new HashMap<String, String>(map));
map.clear();
map.put(SQLiteHelper.KEY_1, "Value 1C");
map.put(SQLiteHelper.KEY_2, "Value 2C");
map.put(SQLiteHelper.KEY_3, "Value 3C");
MY_DEFAULTS.add(new HashMap<String, String>(map));
//and so on
}
}
And then in my SQLiteDatasource class I have a method that performs the insert of these default values:
public void preloadDefaults() {
mDatabase.beginTransaction();
try {
for (HashMap<String, String> map : MyDefaults.MY_DEFAULTS) {
ContentValues values = new ContentValues();
values.put(SQLiteHelper.KEY_1, map.get(SQLiteHelper.KEY_1));
values.put(SQLiteHelper.KEY_2, map.get(SQLiteHelper.KEY_2));
values.put(SQLiteHelper.KEY_3, map.get(SQLiteHelper.KEY_3));
mDatabase.insert(SQLiteHelper.SOME_TABLE, null, values);
}
}
finally {
mDatabase.endTransaction();
}
}
Is my way of doing this considered bad practice? Is there a better way to define the "defaults" that get inserted into a table after it gets created? Possibly through XML instead of a static class?
Note: I can't just copy an external DB because I'm actually inserting these fields with some other values created at runtime (the code above is a simplification of what my real code is).
As it is in this answer also
The SQLiteAssetHelper library makes this task really simple.
It's easy to add as a gradle dependency (but a Jar is also available for Ant/Eclipse), and together with the documentation it can be found at:
https://github.com/jgilfelt/android-sqlite-asset-helper
As explained in documentation:
Add the dependency to your module's gradle build file:
dependencies {
compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
}
Copy the database into the assets directory, in a subdirectory called assets/databases. For instance:
assets/databases/my_database.db
(Optionally, you may compress the database in a zip file such as assets/databases/my_database.zip. This isn't needed, since the APK is compressed as a whole already.)
Create a class, for example:
public class MyDatabase extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "my_database.db";
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
You can memorize your data, with Serialize Objects. Read here:
How do I serialize an object and save it to a file in Android?

Can you use the DBFlow Android ORM with an existng Database Packaged with the app?

Can you use the DbFlow ORM with an existing SQLite Database. That is packaged with the app and copied (from assets folder) over on initial install?
Add your db foo.db in the assets folder and set your database class FooDatabase as the follow:
#Database(name = FooDatabase.NAME, version = FooDatabase.VERSION)
public class FooDatabase {
public static final String NAME = "foo";
public static final int VERSION = 1;
}
note the name is the same without the .db.
Now suppose you have a table FooTable with a column id and a column fooName, we needs to represent that table as the follow:
import com.raizlabs.android.dbflow.structure.BaseModel;
#Table(databaseName = FooDatabase.NAME)
public class FooTable extends BaseModel {
#Column #PrimaryKey(autoincrement = true) long id;
#Column String fooName;
}
it is all, test it, add some values to db and log it to show:
List foo = new Select().from(FooTable.class).queryList()

android sqllite cannot be accessed from outside package

I am making an Android app to learn sqllite. Because I use 7 tables, I decided to create 7 class files in a folder "DBHelper", and want to make 7 files in a folder "DBadapter". Here what the structure looks like:
root
DBHelper: 7 helper files (ex: PersonHelper.java)
DBadapter: 7 adapter files (ex: PersonDAO.java)
But I get an error message with PersonDAO.java: "cannot be accessed from outside package", when I declared the object: "PersonHelper personHelper = new PersonHelper(context);" in the constructor.
Anyone has an idea how to fix that without putting all files in one folder? What is the standard in the industry when creating multiple large tables?
PS: The error is gone once I place all files in one directory.
public class PersonDAO {
private Context context;
//Database info
private static final String DATABASE_NAME = "MyDB";
private static final int DATABASE_VERSION = 1;
//Table helper info
public PersonHelper databaseHelper;
private SQLiteDatabase db = null;
//Constructors
PersonDAO(Context context) {
this.context = context;
databaseHelper = new PersonHelper(context); //Error: "cannot be accessed from outside package"
}
Your constructor of your PersonHelper is probably default like it is in your PersonDAO class. So it can only be accessed from the same package. You have to change it to public to access it from PersonDAO:
public PersonHelper(Context context){
...
}

Get databases directory for my app programmatically

I want to use a "pre loaded" database in my app. There are tons of questions about this and most point to this blog article here or similars.
So far so good. I just want to know if there is a better way to get the default databases directory so you don't have to use something like this:
private static String DB_PATH = "/data/data/YOUR_PACKAGE/databases/";
I mean, maybe that is changed in the future or maybe a device or rom could place it elsewhere... so is there a way to get this path programatically?
In Context exists a method to getDatabasePath(name), but you need to give it an existing db name and well... it doesn't exist yet, I want to move it there :P
I used...
String destPath = getFilesDir().getPath();
destPath = destPath.substring(0, destPath.lastIndexOf("/")) + "/databases";
Create an empty DB, get the path with getDatabasePath(), then overwrite it with your own.
Used by SQLiteAssetHelper:
String path = mContext.getDatabasePath(mName).getPath();
At this time, the database doesn't exist. I think the String just takes the internal path and adds the appropriate modifiers. In fact, this seems to work just fine:
context.getDatabasePath("a").getParentFile()
Basically, you don't need to have a real database created, just ask it for one.
You can use the Method getFilesDir() or getDatabasePath in an Activity-Class to get this Folder.
More info here
You can use getDatabasePath method in your Helper class:
public class MyDatabase extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "wl.db";
private static final int DATABASE_VERSION = 1;
public String databasePath = "";
public MyDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// you can use an alternate constructor to specify a database location
// (such as a folder on the sd card)
// you must ensure that this folder is available and you have permission
// to write to it
// super(context, DATABASE_NAME, context.getExternalFilesDir(null).getAbsolutePath(), null, DATABASE_VERSION);
databasePath = context.getDatabasePath("wl.db").getPath();
}

Categories

Resources