Skip to content

Commit

Permalink
Use SAF when available for exporting the database file
Browse files Browse the repository at this point in the history
Signed-off-by: Daniele Ricci <[email protected]>
  • Loading branch information
daniele-athome committed Nov 19, 2020
1 parent 8f48a3f commit 2a126f2
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ public void onPassphraseChanged(String passphrase) {
Context ctx = getContext();
if (ctx != null) {
new FolderChooserDialog.Builder(ctx)
.tag(AccountFragment.this.getClass().getName())
.initialPath(PersonalKeyPack.DEFAULT_KEYPACK.getParent())
.show(getParentFragmentManager());
}
Expand Down
88 changes: 81 additions & 7 deletions app/src/main/java/org/kontalk/ui/prefs/CopyDatabasePreference.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,25 @@
package org.kontalk.ui.prefs;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;

import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import android.util.AttributeSet;
import android.widget.Toast;

import org.kontalk.Kontalk;
import org.kontalk.Log;
import org.kontalk.R;
import org.kontalk.provider.MessagesProvider;
import org.kontalk.reporting.ReportingManager;
import org.kontalk.util.DataUtils;
import org.kontalk.util.MediaStorage;

import java.io.File;
import java.io.FileInputStream;
Expand All @@ -37,12 +46,22 @@
import java.io.InputStream;
import java.io.OutputStream;

import com.afollestad.materialdialogs.folderselector.FolderChooserDialog;


/**
* Preference for copying the messages database to the external storage.
* @author Daniele Ricci
*/
public class CopyDatabasePreference extends Preference {
private static final String TAG = Kontalk.TAG;

public static final int REQUEST_COPY_DATABASE = Activity.RESULT_FIRST_USER + 4;

private static final String DBFILE_MIME = "application/x-sqlite3";
public static final String DBFILE_NAME = "kontalk-messages.db";

private Fragment mFragment;

public CopyDatabasePreference(Context context) {
super(context);
Expand All @@ -69,25 +88,80 @@ private void init() {
setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
copyDatabase(getContext());
requestFile(getContext());
return true;
}
});
}

void copyDatabase(Context context) {
MessagesProvider.lockForImport(context);
public void setParentFragment(Fragment fragment) {
mFragment = fragment;
}

InputStream dbIn = null;
void requestFile(Context context) {
try {
if (MediaStorage.isStorageAccessFrameworkAvailable()) {
MediaStorage.createFile(mFragment, DBFILE_MIME, DBFILE_NAME,
REQUEST_COPY_DATABASE);
return;
}
}
catch (ActivityNotFoundException e) {
Log.w(TAG, "Storage Access Framework not working properly");
ReportingManager.logException(e);
}

// also used as a fallback if SAF is not working properly
Context ctx = getContext();
if (ctx != null) {
new FolderChooserDialog.Builder(ctx)
.tag(getClass().getName())
.initialPath(Environment.getExternalStorageDirectory().toString())
.show(mFragment.getParentFragmentManager());
}
}

public static void copyDatabase(Context context, File dbOutFile) {
OutputStream dbOut = null;
try {
File dbOutFile = new File(Environment.getExternalStorageDirectory(), "kontalk-messages.db");
dbOut = new FileOutputStream(dbOutFile);
copyDatabase(context, dbOut, dbOut.toString());
}
catch (IOException e) {
Toast.makeText(context, context
.getString(R.string.msg_copy_database_failed, e.toString()), Toast.LENGTH_LONG)
.show();
}
finally {
DataUtils.close(dbOut);
}
}

public static void copyDatabase(Context context, Uri dbOutFile) {
OutputStream dbOut = null;
try {
dbOut = context.getContentResolver().openOutputStream(dbOutFile);
copyDatabase(context, dbOut, dbOutFile.toString());
}
catch (IOException e) {
Toast.makeText(context, context
.getString(R.string.msg_copy_database_failed, e.toString()), Toast.LENGTH_LONG)
.show();
}
finally {
DataUtils.close(dbOut);
}
}

private static void copyDatabase(Context context, OutputStream dbOut, String filename) {
MessagesProvider.lockForImport(context);

InputStream dbIn = null;
try {
dbIn = new FileInputStream(MessagesProvider.getDatabaseUri(context));
dbOut = new FileOutputStream(dbOutFile);
DataUtils.copy(dbIn, dbOut);
Toast.makeText(context, context
.getString(R.string.msg_copy_database_success, dbOutFile.toString()), Toast.LENGTH_LONG)
.getString(R.string.msg_copy_database_success, filename), Toast.LENGTH_LONG)
.show();
}
catch (IOException e) {
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/java/org/kontalk/ui/prefs/MaintenanceFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@

package org.kontalk.ui.prefs;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference;

Expand Down Expand Up @@ -53,6 +57,10 @@ public boolean onPreferenceClick(Preference preference) {
}
});

// send our stuff to the copy database preference
final CopyDatabasePreference copyDatabase = findPreference("pref_copy_database");
copyDatabase.setParentFragment(this);

if (Kontalk.get().getDefaultAccount() == null) {
// no account, hide/disable some stuff
restartMsgCenter.setEnabled(false);
Expand All @@ -74,4 +82,18 @@ public void onResume() {
.setTitle(R.string.pref_maintenance);
}

@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == CopyDatabasePreference.REQUEST_COPY_DATABASE) {
if (resultCode == Activity.RESULT_OK) {
Context ctx = getActivity();
if (ctx != null && data != null && data.getData() != null) {
CopyDatabasePreference.copyDatabase(ctx, data.getData());
}
}
}
else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
27 changes: 17 additions & 10 deletions app/src/main/java/org/kontalk/ui/prefs/PreferencesActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,24 @@ public void onNestedPreferenceSelected(int key) {

@Override
public void onFolderSelection(@NonNull FolderChooserDialog folderChooserDialog, @NonNull File folder) {
try {
AccountFragment f = (AccountFragment) getSupportFragmentManager()
.findFragmentById(R.id.container);
f.exportPersonalKey(this,
new FileOutputStream(new File(folder, PersonalKeyPack.KEYPACK_FILENAME)));
final String tag = folderChooserDialog.getTag();
if (tag.equals(CopyDatabasePreference.class.getName())) {
CopyDatabasePreference.copyDatabase(this,
new File(folder, CopyDatabasePreference.DBFILE_NAME));
}
catch (FileNotFoundException e) {
Log.e(PreferencesFragment.TAG, "error exporting keys", e);
Toast.makeText(this,
R.string.err_keypair_export_write,
Toast.LENGTH_LONG).show();
else if (tag.equals(AccountFragment.class.getName())) {
try {
AccountFragment f = (AccountFragment) getSupportFragmentManager()
.findFragmentById(R.id.container);
f.exportPersonalKey(this,
new FileOutputStream(new File(folder, PersonalKeyPack.KEYPACK_FILENAME)));
}
catch (FileNotFoundException e) {
Log.e(PreferencesFragment.TAG, "error exporting keys", e);
Toast.makeText(this,
R.string.err_keypair_export_write,
Toast.LENGTH_LONG).show();
}
}
}

Expand Down

0 comments on commit 2a126f2

Please sign in to comment.