Basic database import and export (to external storage)
(In the Debug Activity)
This commit is contained in:
parent
b9d5fc6572
commit
cc549a6c49
|
@ -13,20 +13,34 @@ import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
|
|
||||||
|
|
||||||
public class DebugActivity extends Activity {
|
public class DebugActivity extends Activity {
|
||||||
Button sendSMSButton;
|
private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class);
|
||||||
Button sendEmailButton;
|
|
||||||
Button incomingCallButton;
|
private Button sendSMSButton;
|
||||||
Button outgoingCallButton;
|
private Button sendEmailButton;
|
||||||
Button startCallButton;
|
private Button incomingCallButton;
|
||||||
Button endCallButton;
|
private Button outgoingCallButton;
|
||||||
Button testNotificationButton;
|
private Button startCallButton;
|
||||||
Button setMusicInfoButton;
|
private Button endCallButton;
|
||||||
Button setTimeButton;
|
private Button testNotificationButton;
|
||||||
Button rebootButton;
|
private Button setMusicInfoButton;
|
||||||
EditText editContent;
|
private Button setTimeButton;
|
||||||
|
private Button rebootButton;
|
||||||
|
private Button exportDBButton;
|
||||||
|
private Button importDBButton;
|
||||||
|
private EditText editContent;
|
||||||
|
|
||||||
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,6 +128,21 @@ public class DebugActivity extends Activity {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exportDBButton = (Button) findViewById(R.id.exportDBButton);
|
||||||
|
exportDBButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
exportDB();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
importDBButton = (Button) findViewById(R.id.importDBButton);
|
||||||
|
importDBButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
importDB();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
rebootButton = (Button) findViewById(R.id.rebootButton);
|
rebootButton = (Button) findViewById(R.id.rebootButton);
|
||||||
rebootButton.setOnClickListener(new View.OnClickListener() {
|
rebootButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -156,6 +185,34 @@ public class DebugActivity extends Activity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void exportDB() {
|
||||||
|
try {
|
||||||
|
ActivityDatabaseHandler dbHandler = GBApplication.getActivityDatabaseHandler();
|
||||||
|
DBHelper helper = new DBHelper(this);
|
||||||
|
File dir = FileUtils.getExternalFilesDir();
|
||||||
|
File destFile = helper.exportDB(dbHandler, dir);
|
||||||
|
Toast.makeText(this, "Exported to: " + destFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOG.error("Unable to export db", ex);
|
||||||
|
Toast.makeText(this, "Error exporting DB: " + ex.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importDB() {
|
||||||
|
try {
|
||||||
|
ActivityDatabaseHandler dbHandler = GBApplication.getActivityDatabaseHandler();
|
||||||
|
DBHelper helper = new DBHelper(this);
|
||||||
|
File dir = FileUtils.getExternalFilesDir();
|
||||||
|
File sourceFile = new File(dir, dbHandler.getDatabaseName());
|
||||||
|
helper.importDB(dbHandler, sourceFile);
|
||||||
|
helper.validateDB(dbHandler);
|
||||||
|
Toast.makeText(this, "Import successful.", Toast.LENGTH_LONG).show();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOG.error("Unable to import db", ex);
|
||||||
|
Toast.makeText(this, "Error importing DB: " + ex.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void testNotification() {
|
private void testNotification() {
|
||||||
NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this);
|
NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this);
|
||||||
|
|
|
@ -12,8 +12,10 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler;
|
import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
|
|
||||||
public class GBApplication extends Application {
|
public class GBApplication extends Application {
|
||||||
private static GBApplication context;
|
private static GBApplication context;
|
||||||
|
@ -47,20 +49,15 @@ public class GBApplication extends Application {
|
||||||
|
|
||||||
private void setupLogging() {
|
private void setupLogging() {
|
||||||
if (isFileLoggingEnabled()) {
|
if (isFileLoggingEnabled()) {
|
||||||
File dir = getExternalFilesDir(null);
|
try {
|
||||||
if (dir != null) {
|
File dir = FileUtils.getExternalFilesDir();
|
||||||
if (!dir.exists()) {
|
|
||||||
dir.mkdirs();
|
|
||||||
}
|
|
||||||
// used by assets/logback.xml since the location cannot be statically determined
|
// used by assets/logback.xml since the location cannot be statically determined
|
||||||
System.setProperty("GB_LOGFILES_DIR", dir.getAbsolutePath());
|
System.setProperty("GB_LOGFILES_DIR", dir.getAbsolutePath());
|
||||||
} else {
|
} catch (IOException ex) {
|
||||||
Log.e("GBApplication", "External files dir is null, cannot log to file");
|
Log.e("GBApplication", "External files dir not available, cannot log to file, ex");
|
||||||
System.setProperty("GB_LOGFILES_DIR", "/dev/null");
|
System.setProperty("GB_LOGFILES_DIR", "/dev/null");
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
System.setProperty("GB_LOGFILES_DIR", "/dev/null"); // just to please logback configuration, not used at all
|
|
||||||
try {
|
try {
|
||||||
ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||||
root.detachAppender("FILE");
|
root.detachAppender("FILE");
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.database;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
|
|
||||||
|
public class DBHelper {
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public DBHelper(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getClosedDBPath(SQLiteOpenHelper dbHandler) throws IllegalStateException {
|
||||||
|
SQLiteDatabase db = dbHandler.getReadableDatabase();
|
||||||
|
String path = db.getPath();
|
||||||
|
db.close(); // reference counted, so may still be open
|
||||||
|
if (db.isOpen()) {
|
||||||
|
throw new IllegalStateException("Database must be closed");
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File exportDB(SQLiteOpenHelper dbHandler, File toDir) throws IllegalStateException, IOException {
|
||||||
|
String dbPath = getClosedDBPath(dbHandler);
|
||||||
|
File sourceFile = new File(dbPath);
|
||||||
|
File destFile = new File(toDir, sourceFile.getName());
|
||||||
|
if (destFile.exists()) {
|
||||||
|
File backup = new File(toDir, destFile.getName() + "_" + getDate());
|
||||||
|
destFile.renameTo(backup);
|
||||||
|
} else if (!toDir.exists()) {
|
||||||
|
if (!toDir.mkdirs()) {
|
||||||
|
throw new IOException("Unable to create directory: " + toDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtils.copyFile(sourceFile, destFile);
|
||||||
|
return destFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDate() {
|
||||||
|
return new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.US).format(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void importDB(SQLiteOpenHelper dbHandler, File fromFile) throws IllegalStateException, IOException {
|
||||||
|
String dbPath = getClosedDBPath(dbHandler);
|
||||||
|
File toFile = new File(dbPath);
|
||||||
|
FileUtils.copyFile(fromFile, toFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateDB(SQLiteOpenHelper dbHandler) throws IOException {
|
||||||
|
try (SQLiteDatabase db = dbHandler.getReadableDatabase()) {
|
||||||
|
if (!db.isDatabaseIntegrityOk()) {
|
||||||
|
throw new IOException("Database integrity is not OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
|
||||||
|
public class FileUtils {
|
||||||
|
/**
|
||||||
|
* Copies the the given sourceFile to destFile, overwriting it, in case it exists.
|
||||||
|
* @param sourceFile
|
||||||
|
* @param destFile
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void copyFile(File sourceFile, File destFile) throws IOException {
|
||||||
|
if (!sourceFile.exists()) {
|
||||||
|
throw new IOException("Does not exist: " + sourceFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
copyFile(new FileInputStream(sourceFile), new FileOutputStream(destFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copyFile(FileInputStream sourceStream, FileOutputStream destStream) throws IOException {
|
||||||
|
try (FileChannel fromChannel = sourceStream.getChannel(); FileChannel toChannel = destStream.getChannel()) {
|
||||||
|
fromChannel.transferTo(0, fromChannel.size(), toChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the existing external storage dir.
|
||||||
|
* @throws IOException when the directory is not available
|
||||||
|
*/
|
||||||
|
public static File getExternalFilesDir() throws IOException {
|
||||||
|
File dir = GBApplication.getContext().getExternalFilesDir(null);
|
||||||
|
if (dir == null) {
|
||||||
|
throw new IOException("Unable to access external files dir: null");
|
||||||
|
}
|
||||||
|
if (!dir.exists() && !dir.mkdirs()) {
|
||||||
|
throw new IOException("Unable to access external files dir: does not exist");
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,4 +109,23 @@
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignEnd="@+id/endCallButton" />
|
android:layout_alignEnd="@+id/endCallButton" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Export DB"
|
||||||
|
android:id="@+id/exportDBButton"
|
||||||
|
android:layout_above="@+id/rebootButton"
|
||||||
|
android:layout_alignEnd="@+id/textView"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:singleLine="false" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Import DB"
|
||||||
|
android:id="@+id/importDBButton"
|
||||||
|
android:layout_alignTop="@+id/exportDBButton"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_toEndOf="@+id/exportDBButton" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
Loading…
Reference in New Issue